package com.cloudkinto.service.platform.impl;

import cn.afterturn.easypoi.csv.entity.CsvExportParams;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cloudkinto.common.RabbitQueueConstant;
import com.cloudkinto.common.RedisKeyConstants;
import com.cloudkinto.common.common.DateUtils;
import com.cloudkinto.common.constant.GlobalConstants;
import com.cloudkinto.common.constant.SysConstant;
import com.cloudkinto.common.utils.CsvUtils;
import com.cloudkinto.common.utils.RakutenUtil;
import com.cloudkinto.common.utils.ali.AliOss;
import com.cloudkinto.common.utils.dict.StaticDict;
import com.cloudkinto.dao.*;
import com.cloudkinto.dto.platform.order.PlatformOrderDto;
import com.cloudkinto.dto.platform.rakuten.OrderRakutenStatusDto;
import com.cloudkinto.entity.*;
import com.cloudkinto.enumType.common.CountryEnum;
import com.cloudkinto.enumType.operate.OperateTypeEnum;
import com.cloudkinto.service.consumer.vo.StockToPlatformConsumerReq;
import com.cloudkinto.service.consumer.vo.order.PlatformOrderCancelReq;
import com.cloudkinto.service.consumer.vo.order.UpdateInventoryLessReq;
import com.cloudkinto.service.consumer.vo.orderSyncRecord.PlatformOrderSyncRecordReq;
import com.cloudkinto.service.consumer.vo.rakuten.*;
import com.cloudkinto.service.mail.MailAccountService;
import com.cloudkinto.service.mail.SendMailService;
import com.cloudkinto.service.mail.vo.SendMailConsumerReq;
import com.cloudkinto.service.order.PlatformOrderCopyService;
import com.cloudkinto.service.platform.*;
import com.cloudkinto.service.platform.sync.vo.SyncRecordItemReq;
import com.cloudkinto.service.platform.vo.AsyncFinishConsumerReq;
import com.cloudkinto.service.platform.vo.AsyncUpdateConsumerReq;
import com.cloudkinto.service.platform.vo.StockToPlatformRecordVo;
import com.cloudkinto.service.platform.vo.rakuten.*;
import com.cloudkinto.service.platform.vo.rakuten.ConfirmMessageModel;
import com.cloudkinto.service.platform.vo.rakuten.stock.InventoryRakutenReq;
import com.cloudkinto.service.platform.vo.rakuten.stock.RakutenInventory;
import com.cloudkinto.service.platform.vo.rakuten.stock.InventoryRakutenEntity;
import com.cloudkinto.vo.stock.PlatformSkuStockDto;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.DefaultTypedTuple;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.math.BigDecimal;
import java.time.LocalTime;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Transactional(rollbackFor = Exception.class)//事务回滚
@Slf4j
@RequiredArgsConstructor
public class PlatformOrderRakutenSyncServiceImpl extends ServiceImpl<PlatformOrderDao, PlatformOrderDo> implements PlatformOrderRakutenSyncService {
    private final PlatformStoreDao platformStoreDao;
    private final PlatformOrderDao platformOrderDao;
    private final RabbitTemplate rabbitTemplate;
    private final PlatformOrderProductDao platformOrderProductDao;
    private final PlatformOrderService platformOrderService;
    private final PlatformStoreService platformStoreService;
    private final RakutenMarkRecordService rakutenMarkRecordService;
    private final RakutenMarkRecordOrderService rakutenMarkRecordOrderService;
    protected final RedisTemplate redisTemplate;
    private final PlatformProductService platformProductService;
    @Value("${gbc.customer}")
    private String customer;
    private final PlatformOrderCopyService platformOrderCopyService;
    private final SendMailService sendMailService;
    private final MailAccountService mailAccountService;
    private final MailAccountDao mailAccountDao;
    private final ThreadPoolTaskExecutor taskExecutor;
    private final ProductStockDao productStockDao;
    @Value("${gbc.exportPath.omsFilePath}")
    private String omsFilePath;
    @Value("${gbc.uploadPath.omsFileUrl}")
    private String omsFileUrl;
    @Value("${gbc.uploadPath.fileUrl}")
    private String fileUrl;
    @Value("${gbc.uploadPath.filePath}")
    private String filePath;
    private final AsyncJobDao asyncJobDao;
    private final PlatformOrderSyncRecordDao platformOrderSyncRecordDao;

    /**
     * 自动确认订单 默认同步 100 的订单 近7天
     */
    @Override
    public void platOrderAutoConfirm() {
        if (!StaticDict.Company_Type.Labella.getValue().equals(customer) && !StaticDict.Company_Type.Lemooli.getValue().equals(customer)) {
            return;
        }
        List<PlatformStoreDo> storeDoList = platformStoreDao.selectList(new LambdaQueryWrapper<PlatformStoreDo>().eq(PlatformStoreDo::getPlatformCode, "rakuten")
//                        .eq(PlatformStoreDo::getId, 9L) ////ip被封了 再另一个服务器同步 Rakuten-SPORTS数据
                .eq(PlatformStoreDo::getAuthSyncStatus, 1).isNotNull(PlatformStoreDo::getAppSecret));
        for (PlatformStoreDo platformStoreDo : storeDoList) {
            rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_Rakuten_AutoConfirm, platformStoreDo.getId());
        }
    }


    @Override
    public String autoConfirmOrder(Long storeId) {
        PlatformStoreDo storeDo = platformStoreDao.selectById(storeId);
        if (storeDo == null || StringUtils.isBlank(storeDo.getAppSecret())) {
            return ("店铺对应平台Token未绑定");
        }

        Set<String> allOrderIds = new TreeSet<>();
        String url = GlobalConstants.RakutenURL + "/order/searchOrder/";
        int count = 1000;
        int pageNo = 1;
        int totalPages = 0;
        do {
            Map<String, Object> map = new JSONObject();
            map.put("startDatetime", DateUtils.dateFormatToString(DateUtils.passingDate(new Date(), -7), "yyyy-MM-dd'T'HH:mm:ss+0900"));
            map.put("endDatetime", DateUtils.dateFormatToString(new Date(), "yyyy-MM-dd'T'HH:mm:ss+0900"));
            map.put("dateType", 1);//1,订单创建时间 3订单支付时间
            map.put("orderProgressList", new int[]{100});
            Map<String, Object> page = new HashMap<>();
            page.put("requestRecordsAmount", count);
            page.put("requestPage", pageNo);
            map.put("PaginationRequestModel", page);
            String jsonData = RakutenUtil.raAPidoPOST(url, storeDo.getAppSecret(), storeDo.getAppKey(), map);
//            log.error("乐天订单100订单返回值:" + jsonData);
            if (StringUtils.isBlank(jsonData)) {
                return "连接超时";
            }
            JSONObject object = JSONObject.parseObject(jsonData);
            JSONArray messageModelList = object.getJSONArray("MessageModelList");
            //{ "Results": { "errorCode": "ES01-01", "message": "Un-Authorised"}}
            if (messageModelList == null) {
                JSONObject jsonObject1 = object.getJSONObject("Results");
                if (jsonObject1 != null) {
                    if (jsonObject1.getString("errorCode") != null && "ES01-01".equals(jsonObject1.getString("errorCode"))) {
                        //授权过期，把店铺授权状态改为过期状态 todo
                        platformStoreService.updateStoreAuthStatus(storeDo.getId());
                    }
                }
                return jsonObject1 == null ? "Results null" : jsonObject1.toJSONString();
            }
            if ("ERROR".equals(messageModelList.getJSONObject(0).getString("messageType"))) {
                //错误的情况
                String message = messageModelList.getJSONObject(0).getString("message");
//                log.error(storeDo.getStoreName() + " 店铺同步乐天订单错误：" + message);
                return message;
            } else {
                //分页信息
                JSONObject paginationResponseModel = object.getJSONObject("PaginationResponseModel");
                totalPages = paginationResponseModel.getIntValue("totalPages");
                pageNo = paginationResponseModel.getIntValue("requestPage");
                pageNo++;
                String[] orderIds = object.getJSONArray("orderNumberList").toJavaObject(String[].class);
                if (orderIds.length > 0) {
                    allOrderIds.addAll(Arrays.asList(orderIds));
                }
            }
        } while (pageNo <= totalPages);
        RakutenApiRes apiRes = this.getOrder(allOrderIds, storeDo);
        //组装
        //要插入的
        List<PlatformOrderDo> platInertList = new ArrayList<>();
        //子表插入的
        List<PlatformOrderProductDo> platInsetItems = new ArrayList<>();

        for (RakutenOrderModel amzOrder : apiRes.getData()) {

            PlatformOrderDo orderDo = new PlatformOrderDo();
            orderDo.setCompanyId(storeDo.getCompanyId());
            orderDo.setTenantId(storeDo.getTenantId());
            orderDo.setPlatformCode(storeDo.getPlatformCode());
            orderDo.setStoreId(storeDo.getId());
            orderDo.setSite(storeDo.getSite());
            orderDo.setOrderTime(this.replaceStrDateFormat(amzOrder.getOrderDatetime()));
            orderDo.setPayTime(this.replaceStrDateFormat(amzOrder.getOrderFixDatetime()));
            orderDo.setLastUpdateDate(null);
            orderDo.setPlatformOrderNo(amzOrder.getOrderNumber());
            orderDo.setDeliveryDate(amzOrder.getDeliveryDate());
            //解析 指定配达时间带
            if (!org.springframework.util.StringUtils.isEmpty(amzOrder.getShippingTerm()) && !"0".equals(amzOrder.getShippingTerm())) {
                if (amzOrder.getShippingTerm().length() > 3) {
                    orderDo.setDeliveryTimeName(amzOrder.getShippingTerm().substring(0, 2) + "-" + amzOrder.getShippingTerm().substring(2));
                } else if (amzOrder.getShippingTerm().length() > 1) {
                    orderDo.setDeliveryTimeName(amzOrder.getShippingTerm().substring(0, 1) + "-" + amzOrder.getShippingTerm().substring(1));
                } else if (amzOrder.getShippingTerm().equals("1")) {
                    orderDo.setDeliveryTimeName("08-12");
                }
            } else {
                orderDo.setDeliveryTimeName("");
            }
            // orderDo.setDeliveryTimeName(amzOrder.getShippingTerm());
            orderDo.setRemark(amzOrder.getMemo());
            orderDo.setStatus(StaticDict.Platform_Order_Status.Zero.getValue());

            //支付方式
            if (amzOrder.getSettlementModel() != null) {
                orderDo.setSettlementModel(amzOrder.getSettlementModel().getSettlementMethod());
            }

            //买家信息
            if (amzOrder.getOrdererModel() != null) {
                orderDo.setBuyerName(amzOrder.getOrdererModel().getBuyerName());
                orderDo.setBuyerEmail(amzOrder.getOrdererModel().getEmailAddress());
                orderDo.setBuyerPostcode(amzOrder.getOrdererModel().getZipCode());
                orderDo.setBuyerAddress(amzOrder.getOrdererModel().getAddress());
                orderDo.setBuyerTelephone(amzOrder.getOrdererModel().getPhoneNumber());
            }
            //总金额
            if (amzOrder.getTotalPrice() != null) {
                orderDo.setTotalAmount(BigDecimal.valueOf(amzOrder.getTotalPrice()));
                orderDo.setCurrencyCode(CountryEnum.JP.getCurrency());
            }
            if (amzOrder.getPostagePrice() != null) {
                orderDo.setPostagePrice(BigDecimal.valueOf(amzOrder.getPostagePrice()));
            }
            if (amzOrder.getTaxSummaryModelList() != null && !amzOrder.getTaxSummaryModelList().isEmpty()) {
                orderDo.setTaxRate(amzOrder.getTaxSummaryModelList().get(0).getTaxRate());
                orderDo.setReqPrice(amzOrder.getTaxSummaryModelList().get(0).getReqPrice());//含税
                orderDo.setReqPriceTax(amzOrder.getTaxSummaryModelList().get(0).getReqPriceTax());
                orderDo.setCoupon(amzOrder.getTaxSummaryModelList().get(0).getCouponPrice());
            }
            if (amzOrder.getPointModel() != null) {
                orderDo.setPoint(new BigDecimal(amzOrder.getPointModel().getUsedPoint()));
            }
            orderDo.setOrderType(amzOrder.getOrderType());
            orderDo.setIsolated(amzOrder.getIsolatedIslandFlag());
            orderDo.setReserveFlag(0);
            boolean ciRiDaflag = false;
            int puTongType = 0;//普通单时效类型 0没有 1 1-3天内 2 2-5天内
            Date begin = null;
            Date end = null;
            orderDo.setReserveFlag(0);
            for (PackageModelListEntity packageModelListEntity : amzOrder.getPackageModelList()) {
                for (ItemModelListEntity itemEntity : packageModelListEntity.getItemModelList()) {
                    if (StringUtils.isNotBlank(itemEntity.getDelvdateInfo()) && itemEntity.getDelvdateInfo().contains("【予約】") && itemEntity.getDelvdateInfo().contains("に出荷")) {
                        //获取预约单子表的 预约时间 并更新到主表
                        Calendar c = Calendar.getInstance();
                        c.setTime(orderDo.getOrderTime());
                        int year = c.get(Calendar.YEAR);
                        String dateStr = itemEntity.getDelvdateInfo().substring(itemEntity.getDelvdateInfo().indexOf("【予約】") + 4, itemEntity.getDelvdateInfo().indexOf("に出荷"));
                        Date itemBegin, itemEnd;
                        if (dateStr.contains("旬")) {
                            //中旬 下旬
                            StringBuilder month = new StringBuilder(dateStr.substring(0, dateStr.indexOf("旬") - 2));
                            if (month.length() < 2) {
                                month.insert(0, "0");
                            }
                            itemBegin = DateUtils.stringFormatToDate(year + "-" + month.toString() + "-08");
                            itemEnd = DateUtils.passingDate(itemBegin, 30);
                        } else {
                            String[] split = dateStr.split("〜");
                            //结束日期在订单日期之前     结束年+1  开始日期在订单日期之前 则也+1
                            if (DateUtils.stringFormatToDate(year + "/" + split[1], "yyyy/MM/dd").before(orderDo.getOrderTime())) {
                                //预约结束日期在订单日期之前
                                itemEnd = DateUtils.stringFormatToDate((year + 1) + "/" + split[1], "yyyy/MM/dd");
                                if (DateUtils.stringFormatToDate(year + "/" + split[1], "yyyy/MM/dd").after(DateUtils.stringFormatToDate(year + "/" + split[0], "yyyy/MM/dd"))) {
                                    //预约开始时间 在结束日期之前 就跟着结束日期 一样 +1
                                    itemBegin = DateUtils.stringFormatToDate((year + 1) + "/" + split[0], "yyyy/MM/dd");
                                } else {
                                    itemBegin = DateUtils.stringFormatToDate((year) + "/" + split[0], "yyyy/MM/dd");
                                }
                            } else {
                                itemEnd = DateUtils.stringFormatToDate((year) + "/" + split[1], "yyyy/MM/dd");
                                itemBegin = DateUtils.stringFormatToDate((year) + "/" + split[0], "yyyy/MM/dd");
                            }
                            long day = DateUtil.betweenDay(new Date(), itemBegin, false);
                            if (day > 160) {
                                //如果预约时间 和当前时间 大于160天 则年减-1
                                itemBegin = DateUtils.passingDateYear(itemBegin, -1);
                                itemEnd = DateUtils.passingDateYear(itemEnd, -1);
                            }
                        }
                        if (end == null || itemEnd.after(end)) {
                            end = itemEnd;
                            begin = itemBegin;
                        } else if (itemEnd.getTime() == end.getTime() && (begin == null || itemBegin.after(begin))) {
                            begin = itemBegin;
                        }
                    }
                    //todo 4077 公司 Amazon Yahoo Wowma平台订单 都分成次日达  或者 deliveryDate 不为空
                    else if (StringUtils.isNotBlank(itemEntity.getDelvdateInfo()) &&
                            (itemEntity.getDelvdateInfo().contains("12時まで") || (itemEntity.getDelvdateInfo().contains("決済日から") && StringUtils.isNotBlank(amzOrder.getDeliveryDate())))) {
                        //次日达
                        ciRiDaflag = true;
                    } else {
                        //普通单
                        if (StringUtils.isNotBlank(itemEntity.getDelvdateInfo()) && itemEntity.getDelvdateInfo().contains("1〜3日以内")) {
                            puTongType = 1;
                        } else if (StringUtils.isNotBlank(itemEntity.getDelvdateInfo()) && itemEntity.getDelvdateInfo().contains("2〜5日以内") && puTongType != 1) {
                            puTongType = 2;
                        }
                    }
                }
                orderDo.setReceiver(packageModelListEntity.getSenderModel().getSenderName());
                orderDo.setTelephone(packageModelListEntity.getSenderModel().getPhoneNumber());
                orderDo.setCountryRegionCode(CountryEnum.JP.toString());
                orderDo.setProvinceCode(null);
                orderDo.setProvinceName(null);
                orderDo.setCityCode(packageModelListEntity.getSenderModel().getCity());
                orderDo.setDistrict(packageModelListEntity.getSenderModel().getPrefecture());
                orderDo.setPostcode(packageModelListEntity.getSenderModel().getZipCode());
                orderDo.setHouseNum("");
                orderDo.setAddressOne(packageModelListEntity.getSenderModel().getSubAddress());
                orderDo.setAddressTwo(null);
                orderDo.setBasketId(String.valueOf(packageModelListEntity.getBasketId()));
                break;
            }
            if (end != null) {
                orderDo.setReserveBeginTime(begin);
                orderDo.setReserveEndTime(end);
                orderDo.setReserveFlag(1);
            } else if (ciRiDaflag) {
                orderDo.setReserveFlag(2);
            } else {
                if (puTongType != 0) {
                    //1-3天内
                    orderDo.setReserveBeginTime(orderDo.getOrderTime());
                    String endStr = DateUtils.dateFormatToString(DateUtils.passingDate(orderDo.getReserveBeginTime(), puTongType == 1 ? 3 : 5), "yyyy-MM-dd");
                    endStr += " 23:59:59";
                    orderDo.setReserveEndTime(DateUtils.stringFormatToDateHms(endStr));
                }
            }


            //处理中的状态是否也要过滤
            StringBuilder builder = new StringBuilder();
            for (PackageModelListEntity packageModelListEntity : amzOrder.getPackageModelList()) {
                orderDo.setDefaultDeliveryCompanyCode(packageModelListEntity.getDefaultDeliveryCompanyCode());
                for (ItemModelListEntity itemEntity : packageModelListEntity.getItemModelList()) {
                    PlatformOrderProductDo platItem = new PlatformOrderProductDo();
                    platItem.setPlatformOrderNo(amzOrder.getOrderNumber());
                    platItem.setPlatformParentSku(itemEntity.getManageNumber());
                    platItem.setPlatformSku(itemEntity.getItemNumber());
                    if (itemEntity.getSkuModelList() != null && !itemEntity.getSkuModelList().isEmpty()) {
                        platItem.setPlatformSku(itemEntity.getSkuModelList().get(0).getMerchantDefinedSkuId());
                    }
                    if (StringUtils.isBlank(platItem.getPlatformSku())) {
                        platItem.setPlatformSku(itemEntity.getManageNumber());
                    }
                    platItem.setPlatformProductName(itemEntity.getItemName());
                    platItem.setPlatformQty(itemEntity.getUnits());
                    platItem.setSkuType(1);
                    platItem.setItemAmount(BigDecimal.valueOf(itemEntity.getPrice()));
                    platItem.setCurrencyCode(CountryEnum.JP.getCurrency());
                    StringBuilder skuInfo = new StringBuilder();
                    if (itemEntity.getSkuModelList() != null && !itemEntity.getSkuModelList().isEmpty()) {
                        skuInfo.append(itemEntity.getSkuModelList().get(0).getSkuInfo());
                    }
                    if (StringUtils.isNotBlank(itemEntity.getSelectedChoice())) {
                        if (skuInfo.length() > 0) {
                            skuInfo.append("\n");
                        }
                        skuInfo.append(itemEntity.getSelectedChoice());
                    }
                    platItem.setSkuInfo(skuInfo.toString());
                    if (StringUtils.isNotBlank(builder)) {
                        builder.append(";");
                    }
                    builder.append(platItem.getPlatformSku()).append("*").append(platItem.getPlatformQty());
                    platInsetItems.add(platItem);
                }
            }
            orderDo.setPlatformSku(builder.toString());
            platInertList.add(orderDo);
        }
        //自动确认
        Set<String> objects = platInertList.stream().map(PlatformOrderDo::getPlatformOrderNo).collect(Collectors.toSet());
        List<String> successConfirmOrderNumberList = this.confirmOrder(objects, storeDo);
        //自动发送邮箱
        List<MailAccountDo> mailAccountDos = mailAccountDao.selectList(new LambdaQueryWrapper<MailAccountDo>().eq(MailAccountDo::getStoreId, storeId));
        hanldeAutoSendMail(mailAccountDos, platInertList.stream().filter(i -> successConfirmOrderNumberList.contains(i.getPlatformOrderNo())).collect(Collectors.toList()), platInsetItems);
        return "";
    }

    @Override
    public void hanldeAutoSendMail(List<MailAccountDo> mailAccountDos, List<PlatformOrderDo> platInertList, List<PlatformOrderProductDo> platInsetItems) {
        Map<String, List<PlatformOrderProductDo>> itemMap = platInsetItems
                .stream().collect(Collectors.groupingBy(PlatformOrderProductDo::getPlatformOrderNo));
        List<PlatformOrderDto> platformOrders = new ArrayList<>();
        if (platInertList.isEmpty()) return;
        for (PlatformOrderDo platformOrderDo : platInertList) {
            List<PlatformOrderProductDo> itemList = itemMap.get(platformOrderDo.getPlatformOrderNo());
            if (itemList == null) {
                continue;
            }
            PlatformOrderDto platformOrderDto = new PlatformOrderDto();
            BeanUtils.copyProperties(platformOrderDo, platformOrderDto);
            if (platformOrderDto.getPlatformOrderNo().endsWith("-1") || platformOrderDto.getPlatformOrderNo().endsWith("-2") || platformOrderDto.getPlatformOrderNo().endsWith("-3")
                    || platformOrderDto.getPlatformOrderNo().endsWith("-4") || platformOrderDto.getPlatformOrderNo().endsWith("-5") || platformOrderDto.getPlatformOrderNo().endsWith("-6")) {
                platformOrderDto.setPlatformOrderNo(platformOrderDto.getPlatformOrderNo().substring(0, platformOrderDto.getPlatformOrderNo().length() - 2));
            }
            platformOrderDto.setProductDoList(itemList);
            platformOrders.add(platformOrderDto);
        }
        List<MailAccountDo> mailAccountDoList = mailAccountDos.stream()
                .filter(mailAccountDo -> mailAccountDo.getIsAutoSent() == 1)
                .collect(Collectors.toList());
        sendMailService.autoSendEmail(1, mailAccountDoList, platformOrders);

    }


    public List<String> confirmOrder(Set<String> orderIds, PlatformStoreDo storeDo) {
//        log.error("乐天自动确认订单号：" + orderIds);
        List<String> orderList = new ArrayList<>();
        if (orderIds.isEmpty()) {
            return orderList;
        }
        String url = GlobalConstants.RakutenURL + "/order/confirmOrder/";
        List<List<String>> partition = ListUtil.partition(new ArrayList<>(orderIds), 100);

        for (List<String> orderLimit : partition) {
            Map<String, Object> param = new HashMap<>();
            param.put("orderNumberList", orderLimit);
//            param.put("version", 7);
            String jsonData = "";
            try {
                jsonData = RakutenUtil.raAPidoPOST(url, storeDo.getAppSecret(), storeDo.getAppKey(), param);
                //{ "Results": { "errorCode": "ES01-01", "message": "Un-Authorised"}}
                //{"MessageModelList":[{"messageType":"INFO","messageCode":"ORDER_EXT_API_GET_ORDER_INFO_101","message":"受注情報取得に成功しました。(取得件数1件)"}],"OrderModelList":[{"orderNumber":"369266-20211215-00042704","orderProgress":300,"subStatusId":null,"subStatusName":null,"orderDatetime":"2021-12-15T23:56:00+0900","shopOrderCfmDatetime":"2021-12-16T01:00:01+0900","orderFixDatetime":"2021-12-16T01:03:16+0900","shippingInstDatetime":"2021-12-16T01:03:16+0900","shippingCmplRptDatetime":null,"cancelDueDate":"2022-12-15","deliveryDate":"2021-12-17","shippingTerm":null,"remarks":"[配送日時指定:]\n\n16時過ぎ以降在宅です。\nよろしくお願いします。\n","giftCheckFlag":0,"severalSenderFlag":0,"equalSenderFlag":1,"isolatedIslandFlag":0,"rakutenMemberFlag":1,"carrierCode":12,"emailCarrierCode":0,"orderType":1,"reserveNumber":null,"reserveDeliveryCount":null,"cautionDisplayType":0,"rakutenConfirmFlag":0,"goodsPrice":14280,"goodsTax":0,"postagePrice":0,"deliveryPrice":0,"paymentCharge":0,"paymentChargeTaxRate":0.1,"totalPrice":14280,"requestPrice":13000,"couponAllTotalPrice":0,"couponShopPrice":0,"couponOtherPrice":0,"additionalFeeOccurAmountToUser":0,"additionalFeeOccurAmountToShop":0,"asurakuFlag":1,"drugFlag":0,"dealFlag":0,"membershipType":0,"memo":null,"operator":null,"mailPlugSentence":null,"modifyFlag":0,"receiptIssueCount":0,"receiptIssueHistoryList":[],"OrdererModel":{"zipCode1":"355","zipCode2":"0045","prefecture":"埼玉県","city":"東松山市","subAddress":"宮鼻944-2","familyName":"大湯","firstName":"真沙美","familyNameKana":"オオユ","firstNameKana":"マサミ","phoneNumber1":"0493","phoneNumber2":"34","phoneNumber3":"4466","emailAddress":"2600afad543e82a7a65645b7cc6270b9s1@pc.fw.rakuten.ne.jp","sex":"女","birthYear":1983,"birthMonth":5,"birthDay":25},"SettlementModel":{"settlementMethodCode":1,"settlementMethod":"クレジットカード","rpaySettlementFlag":1,"cardName":"MASTER","cardNumber":"XXXX-XXXX-XXXX-0046","cardOwner":"MASAMI OOYU","cardYm":"2022-05","cardPayType":0,"cardInstallmentDesc":null},"DeliveryModel":{"deliveryName":"宅配便","deliveryClass":null},"PointModel":{"usedPoint":1280},"WrappingModel1":null,"WrappingModel2":null,"PackageModelList":[{"basketId":370494025,"postagePrice":0,"postageTaxRate":0.1,"deliveryPrice":0,"deliveryTaxRate":0.1,"goodsTax":0,"goodsPrice":14280,"totalPrice":14280,"noshi":null,"defaultDeliveryCompanyCode":"1002","packageDeleteFlag":0,"SenderModel":{"zipCode1":"355","zipCode2":"0045","prefecture":"埼玉県","city":"東松山市","subAddress":"宮鼻944-2","familyName":"大湯","firstName":"真沙美","familyNameKana":"オオユ","firstNameKana":"マサミ","phoneNumber1":"0493","phoneNumber2":"34","phoneNumber3":"4466","isolatedIslandFlag":0},"ItemModelList":[{"itemDetailId":370494025,"itemName":"★【クリスマスプレゼントｘP10倍】あす楽送料無料 ゲーミングチェア オフィスチェアMeseracing デスクチェア 高機能チェア パソコンチェア PUレザー 高反発高密度50Dウレタン ゲーム","itemId":10000197,"itemNumber":"mwpo-141PP00141CAA","manageNumber":"mwpo-104","price":14280,"units":1,"includePostageFlag":0,"includeTaxFlag":1,"includeCashOnDeliveryPostageFlag":0,"selectedChoice":"カラー:グレー\n選択:選択\n※納期について、ご確認ください。:確認しました。\n※北海道・離島などの地方では別途追加送料【2500円】がかかります。沖縄県への配送はできかねます。あす楽希望の場合、日付の指定は無しでも大丈夫です。お届け時間帯の指定は可能です。:確認しました。\n※ご注文後の注文内容（カラー）変更はお受付致しかねます。配送先の間違いがございますと、別途【転送料金】が発生します。再度ご確認ください。:確認しました。","pointRate":10,"pointType":1,"inventoryType":2,"delvdateInfo":"午後14時まであす楽対応(日曜日を除く)","restoreInventoryFlag":0,"dealFlag":0,"drugFlag":0,"deleteItemFlag":0,"taxRate":0.1,"priceTaxIncl":14280,"isSingleItemShipping":0}],"ShippingModelList":[],"DeliveryCvsModel":null}],"CouponModelList":null,"ChangeReasonModelList":[{"changeId":1514822970,"changeType":8,"changeTypeDetail":null,"changeReason":null,"changeReasonDetail":null,"changeApplyDatetime":"2021-12-16T01:00:01+0900","changeFixDatetime":"2021-12-16T01:00:01+0900","changeCmplDatetime":"2021-12-16T01:00:01+0900"}],"TaxSummaryModelList":[{"taxRate":0.1,"reqPrice":13000,"reqPriceTax":1181,"totalPrice":14280,"paymentCharge":0,"couponPrice":0,"point":1280}],"DueDateModelList":[]}]}
//                System.out.println("同步的订单：" + jsonData);
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (StringUtils.isBlank(jsonData)) {
                continue;
            }
//            log.error("乐天自动确认订单返回值：" + jsonData);
            JSONObject object = JSONObject.parseObject(jsonData);
            JSONObject result = object.getJSONObject("Results");
            if (result != null) {
                continue;
            }
            if (object.getJSONArray("MessageModelList") == null) {
                continue;
            }
            List<ConfirmMessageModel> orderModels = JSONObject.parseArray(object.getJSONArray("MessageModelList").toJSONString(), ConfirmMessageModel.class);
            orderList.addAll(orderModels.stream().filter(i -> i.getMessageType().equals("INFO")).map(ConfirmMessageModel::getOrderNumber).collect(Collectors.toList()));
        }
        return orderList;
    }


    @Override
    public String manualUpdateRakutenOrders(List<Long> storeIds, Date beginTime, Date endTime, Long companyId) {
        if (storeIds == null || storeIds.isEmpty()) {
            return "店铺不能为空";
        }
        List<PlatformStoreDo> storeDoList = platformStoreDao.selectList(new LambdaQueryWrapper<PlatformStoreDo>().eq(PlatformStoreDo::getPlatformCode, "rakuten")
                .in(PlatformStoreDo::getId, storeIds).eq(PlatformStoreDo::getCompanyId, companyId));
        if (beginTime == null) {
            beginTime = DateUtils.passingDate(new Date(), -2);
        }
        if (endTime == null) {
            endTime = DateUtils.passingDateHour(new Date(), -4);
        }
        for (PlatformStoreDo storeId : storeDoList) {
            RakutenSyncReq consumerReq = new RakutenSyncReq(new int[]{100, 200, 300, 400, 500, 600, 700, 800, 900}, beginTime, endTime, 3, storeId.getId(), storeId.getStoreName());
            rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_Rakuten_Sync, JSON.toJSONString(consumerReq));
        }

        return null;
    }


    @Override
    public void platOrderRakutenSync() {
        List<PlatformStoreDo> storeDoList = platformStoreDao.selectList(new LambdaQueryWrapper<PlatformStoreDo>().eq(PlatformStoreDo::getPlatformCode, "rakuten")
//                        .eq(PlatformStoreDo::getId, 9L) ////ip被封了 再另一个服务器同步 Rakuten-SPORTS数据
                .eq(PlatformStoreDo::getAuthSyncStatus, 1).isNotNull(PlatformStoreDo::getAppSecret));
        Map<Long, Long> storeRecordIdMap = new HashMap<>();
        for (PlatformStoreDo storeDo : storeDoList) {
            PlatformOrderSyncRecordDo recordDo = new PlatformOrderSyncRecordDo(storeDo.getPlatformCode(), storeDo.getId(), 1, 0, 0, new Date(), null, storeDo.getCompanyId());
            platformOrderSyncRecordDao.insert(recordDo);
            storeRecordIdMap.put(storeDo.getId(), recordDo.getId());
        }
        for (PlatformStoreDo storeDo : storeDoList) {
            Long syncRecordId = storeRecordIdMap.get(storeDo.getId());
            if (syncRecordId == null) {
                continue;
            }
            RakutenSyncReq consumerReq = new RakutenSyncReq(new int[]{100, 200, 300, 400, 500, 600, 700, 800, 900},
                    null, null, null, 1, storeDo.getId(), storeDo.getStoreName(), syncRecordId, null);
            rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_Rakuten_Sync, JSON.toJSONString(consumerReq));
        }
    }


    @Override
    public String updateRakutenOrders(RakutenSyncReq req) {
        PlatformStoreDo storeDo = platformStoreDao.selectById(req.getStoreId());
        if (storeDo == null || StringUtils.isBlank(storeDo.getAppSecret())) {
            return ("店铺对应平台Token未绑定");
        }

        boolean flag = req.getStartDatetime() == null && CollUtil.isEmpty(req.getOrderNumbers());
        //自动
        if (req.getStartDatetime() != null && req.getEndDatetime() != null) {
            long l = DateUtil.betweenDay(req.getStartDatetime(), req.getEndDatetime(), true);
            if (l > 30) {
                return "店铺:" + storeDo.getStoreName() + "每次最多同步30天数据";
            }
        }
        boolean zenLiang = true;
        if (flag) { //自动
            Double time = redisTemplate.opsForZSet().score(RedisKeyConstants.orderSyncTimeSet_Rakuten + customer, storeDo.getId());
            long currency = System.currentTimeMillis();
            if (!(time == null || (currency - time) >= 60 * 5 * 1000)) {
//                return "乐天同步订单:"+storeDo.getStoreCode()+",频率过快(5分钟同步一次)";
            }
            //无上次同步时间 或者 上次同步时间在10分钟之前
            redisTemplate.opsForZSet().add(RedisKeyConstants.orderSyncTimeSet_Rakuten + customer, storeDo.getId(), currency - 5 * 1000);
            if (time == null) {
//                req.setStartDatetime(DateUtils.passingDate(new Date(), -3));
                req.setStartDatetime(DateUtil.offsetHour(new Date(), -16));
                zenLiang = false;
            } else {
                req.setStartDatetime(new Date(time.longValue() - 60 * 1000 * 21));
            }
            req.setEndDatetime(new Date(currency));
            long l = DateUtil.betweenDay(req.getStartDatetime(), req.getEndDatetime(), true);
            if (l > 3) {
                req.setStartDatetime(DateUtils.passingDate(new Date(), -3));
            }
        }
        //告诉他正在处理
        rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformOrder_SyncRecord_Update, JSON.toJSONString(new PlatformOrderSyncRecordReq(req.getSyncId(), 1, new Date(), req.getStartDatetime(), req.getEndDatetime())));
        Set<String> allOrderIds = new TreeSet<>();
        if (CollUtil.isEmpty(req.getOrderNumbers())) {//订单号空 则按照时间同步
            String url = GlobalConstants.RakutenURL + "/order/searchOrder/";
            int count = 1000;
            int pageNo = 1;
            int totalPages = 0;
            do {
                Map<String, Object> map = new JSONObject();
                map.put("startDatetime", DateUtils.dateFormatToString(req.getStartDatetime(), "yyyy-MM-dd'T'HH:mm:ss+0900"));
                map.put("endDatetime", DateUtils.dateFormatToString(req.getEndDatetime(), "yyyy-MM-dd'T'HH:mm:ss+0900"));
                map.put("dateType", req.getDateType());//1,订单创建时间 3订单支付时间
                map.put("orderProgressList", req.getOrderStatus());
                Map<String, Object> page = new HashMap<>();
                page.put("requestRecordsAmount", count);
                page.put("requestPage", pageNo);
                map.put("PaginationRequestModel", page);
                log.info("rakuten 店铺：:" + storeDo.getStoreCode() + "同步订单; 请求参数：\r\n" + JSON.toJSONString(map));
                String jsonData = RakutenUtil.raAPidoPOST(url, storeDo.getAppSecret(), storeDo.getAppKey(), map);
                log.info("rakuten 店铺：:" + storeDo.getStoreCode() + "同步订单; 请求响应：\r\n" + jsonData);
                if (StringUtils.isBlank(jsonData)) {
                    if (flag) {
                        redisTemplate.opsForZSet().add(RedisKeyConstants.orderSyncTimeSet_Rakuten + customer, storeDo.getId(), req.getStartDatetime().getTime());
                    }
                    return "连接超时";
                }
                JSONObject object = JSONObject.parseObject(jsonData);
                JSONArray messageModelList = object.getJSONArray("MessageModelList");
                //{ "Results": { "errorCode": "ES01-01", "message": "Un-Authorised"}}
                if (messageModelList == null) {
                    JSONObject jsonObject1 = object.getJSONObject("Results");
                    if (jsonObject1 != null) {
                        if (jsonObject1.getString("errorCode") != null && "ES01-01".equals(jsonObject1.getString("errorCode"))) {
                            //授权过期，把店铺授权状态改为过期状态 todo
                            platformStoreService.updateStoreAuthStatus(storeDo.getId());
                        }
                    }
//                log.error(object.toString());
                    if (flag) {
                        redisTemplate.opsForZSet().add(RedisKeyConstants.orderSyncTimeSet_Rakuten + customer, storeDo.getId(), req.getStartDatetime().getTime());
                    }
                    return jsonObject1 == null ? "Results null" : jsonObject1.toJSONString();
                }
                if ("ERROR".equals(messageModelList.getJSONObject(0).getString("messageType"))) {
                    //错误的情况
                    String message = messageModelList.getJSONObject(0).getString("message");
//                log.error(storeDo.getStoreName() + " 店铺同步乐天订单错误：" + message);
                    if (flag) {
                        redisTemplate.opsForZSet().add(RedisKeyConstants.orderSyncTimeSet_Rakuten + customer, storeDo.getId(), req.getStartDatetime().getTime());
                    }
                    return message;
                } else {
                    //分页信息
                    JSONObject paginationResponseModel = object.getJSONObject("PaginationResponseModel");
                    totalPages = paginationResponseModel.getIntValue("totalPages");
                    pageNo = paginationResponseModel.getIntValue("requestPage");
                    pageNo++;

                    String[] orderIds = object.getJSONArray("orderNumberList").toJavaObject(String[].class);
                    //剔除本地 500 的订单 增加本地300的订单
                    if (orderIds.length > 0) {
                        allOrderIds.addAll(Arrays.asList(orderIds));
                    }
                }
            } while (pageNo <= totalPages);
            log.info("开始同步店铺:" + storeDo.getStoreName() + "的乐天订单; 获取订单号个数：" + allOrderIds.size() + "个");
        }
        else {
            allOrderIds.addAll(req.getOrderNumbers());
        }
        //追加本地未完成的订单 300
        //因为是同步根据 支付时间， 所以截单的订单会同步不到，需要每次都带上待处理的订单
        Object o = redisTemplate.opsForValue().
                get(RedisKeyConstants.orderSyncTimeCountSet_Rakuten + storeDo.getId() + "_" + customer + "_" + DateUtils.dateFormatToString(new Date()));
        //或者当前时间是11点 则也同步全部待处理的订单
        LocalTime now = LocalTime.now();
        int hour = now.getHour();
        if (o == null || Integer.parseInt(o.toString()) % 8 == 0 || hour == 11) {
            int timeCount = o == null ? 0 : Integer.parseInt(o.toString()) + 1;
            redisTemplate.opsForValue().set(RedisKeyConstants.orderSyncTimeCountSet_Rakuten + storeDo.getId() + "_" + customer + "_" + DateUtils.dateFormatToString(new Date()), timeCount, 6 * 60 * 60, TimeUnit.SECONDS);
            List<String> doingOrderIds = platformOrderDao.getDoingRakutenNos(req.getStoreId());
            //这里将 -1 -2 的替换掉 因为要去平台后台获取状态 这里不替换 像乐天请求时再去替换
            allOrderIds.addAll(doingOrderIds);
        }
        else {
            //将近一天未付款的订单加上去
            List<String> orderIds = platformOrderDao.selectList(new LambdaQueryWrapper<PlatformOrderDo>()
                            .select(PlatformOrderDo::getPlatformOrderNo)
                    .eq(PlatformOrderDo::getStoreId, req.getStoreId()).eq(PlatformOrderDo::getStatus, StaticDict.Platform_Order_Status.Zero.getValue())
                    .ge(PlatformOrderDo::getOrderTime, DateUtils.dateFormatToString(DateUtils.passingDateHour(new Date(), -8), "yyyy-MM-dd HH:mm:ss")))
                    .stream().map(PlatformOrderDo::getPlatformOrderNo).collect(Collectors.toList());
            if (!orderIds.isEmpty()) {
                allOrderIds.addAll(orderIds);
            }
        }
        //根据同步下来的订单号 获取本地订单情况
        Map<String, OrderRakutenStatusDto> orderMap = new HashMap<>();
        List<List<String>> partition = ListUtil.partition(new ArrayList<>(allOrderIds), 5000);
        for (List<String> list : partition) {
            //此时 有 -1 -2 的获取不到本地单状态 这里都是原平台单号的订单
            List<OrderRakutenStatusDto> rakutenOrder = platformOrderDao.getRakutenOrder(list, req.getStoreId());
            orderMap.putAll(rakutenOrder.stream().collect(Collectors.toMap(OrderRakutenStatusDto::getPlatformOrderNo,
                    i -> i, (v1, v2) -> v1)));
        }

        RakutenApiRes apiRes = this.getOrder(allOrderIds, storeDo);
        //组装
        //要插入的
        List<PlatformOrderDo> platInertList = new ArrayList<>();
        List<PlatformOrderDo> platUpdateList = new ArrayList<>();
        //子表插入的
        List<PlatformOrderProductDo> platInsetItems = new ArrayList<>();
        List<PlatformOrderProductDo> platUpdateItems = new ArrayList<>();

        Set<String> confirmMaillList = new HashSet<>();
        List<String> splitOrderNumber = new ArrayList<>();
        //这里 要去 获取-1 -2 本地单状态
        for (RakutenOrderModel amzOrder : apiRes.getData()) {
            if (amzOrder.getPackageModelList().size() <= 1) {
                continue;
            }
            int index = 1;
            for (PackageModelListEntity packageModelListEntity : amzOrder.getPackageModelList()) {
                String splitOrderNo = amzOrder.getOrderNumber() + "-" + index;
                if (!orderMap.containsKey(splitOrderNo)) {
                    splitOrderNumber.add(splitOrderNo);
                }
                index++;
            }
        }
        //获取 拆单的本地单状态
        if (!splitOrderNumber.isEmpty()) {
            List<OrderRakutenStatusDto> rakutenOrder = platformOrderDao.getRakutenOrder(splitOrderNumber, req.getStoreId());
            orderMap.putAll(rakutenOrder.stream().collect(Collectors.toMap(OrderRakutenStatusDto::getPlatformOrderNo,
                    i -> i, (v1, v2) -> v1)));
        }
        for (RakutenOrderModel amzOrder : apiRes.getData()) {
            //多包裹 配置 拆单
            Integer index = null;
            if (amzOrder.getPackageModelList().size() > 1) {
                index = 1;
            }
            for (PackageModelListEntity packageModelListEntity : amzOrder.getPackageModelList()) {
                String platformOrderNo = amzOrder.getOrderNumber();
                if (index != null) {
                    platformOrderNo = (platformOrderNo + "-" + index);
                    index++;
                }
                OrderRakutenStatusDto oldOrder = orderMap.get(platformOrderNo);
                if (oldOrder != null &&
                        (StaticDict.Platform_Order_Status.Three.getValue().equals(oldOrder.getStatus()) || StaticDict.Platform_Order_Status.Four.getValue().equals(oldOrder.getStatus()))) {
                    //本地订单是已完成状态
                    continue;
                }
                PlatformOrderDo orderDo = new PlatformOrderDo();
                orderDo.setCompanyId(storeDo.getCompanyId());
                orderDo.setTenantId(storeDo.getTenantId());
                orderDo.setPlatformCode(storeDo.getPlatformCode());
                orderDo.setStoreId(storeDo.getId());
                orderDo.setSite(storeDo.getSite());
                orderDo.setOrderTime(this.replaceStrDateFormat(amzOrder.getOrderDatetime()));
                orderDo.setPayTime(this.replaceStrDateFormat(amzOrder.getOrderFixDatetime()));
                orderDo.setLastUpdateDate(null);
                orderDo.setPlatformOrderNo(platformOrderNo);
                orderDo.setDeliveryDate(amzOrder.getDeliveryDate());
                //解析 指定配达时间带
                //解析 指定配达时间带
                if (!org.springframework.util.StringUtils.isEmpty(amzOrder.getShippingTerm()) && !"0".equals(amzOrder.getShippingTerm())) {
                    if (amzOrder.getShippingTerm().length() > 3) {
                        orderDo.setDeliveryTimeName(amzOrder.getShippingTerm().substring(0, 2) + "-" + amzOrder.getShippingTerm().substring(2));
                    } else if (amzOrder.getShippingTerm().length() > 1) {
                        orderDo.setDeliveryTimeName(amzOrder.getShippingTerm().substring(0, 1) + "-" + amzOrder.getShippingTerm().substring(1));
                    } else if (amzOrder.getShippingTerm().equals("1")) {
                        orderDo.setDeliveryTimeName("08-12");
                    }
                } else {
                    orderDo.setDeliveryTimeName("");
                }
                orderDo.setRemark(amzOrder.getMemo());
                if (amzOrder.getOrderProgress() == 900) {
                    orderDo.setStatus(StaticDict.Platform_Order_Status.Four.getValue());
                    orderDo.setCancelWay(0);
                    if (amzOrder.getChangeReasonModelList() != null) {
                        for (ChangeReasonModelListEntity change : amzOrder.getChangeReasonModelList()) {
                            if (change.getChangeType() == 2) {
                                orderDo.setCancelTime(change.getChangeApplyDatetime());
                                break;
                            }
                        }
                    }
                } else if (amzOrder.getOrderProgress() == 500) {
                    orderDo.setStatus(StaticDict.Platform_Order_Status.Three.getValue());
                    if (StringUtils.isNotBlank(amzOrder.getShopOrderCfmDatetime())) {
                        orderDo.setShipTime(this.replaceStrDateFormat(amzOrder.getShopOrderCfmDatetime()));
                    }
//                orderDo.setMarkShipmentStatus(4);
                } else {
                    if (oldOrder == null) {//只有插入的时候才设置，不然每次更新都会更新成待处理状态
                        orderDo.setStatus(StaticDict.Platform_Order_Status.Zero.getValue());
                    }
                }
                //order的status 等于0 (代表第一次同步) 或者 (order的status 等于0 (代表本地同步过) 并且 oldOrder的status 等于 0 或者 5)
                boolean status0Flag = StaticDict.Platform_Order_Status.Zero.getValue().equals(orderDo.getStatus()) ||
                        (orderDo.getStatus() == null && oldOrder != null && (StaticDict.Platform_Order_Status.Zero.getValue().equals(oldOrder.getStatus())
                                || StaticDict.Platform_Order_Status.Five.getValue().equals(oldOrder.getStatus())
                        ));
                //判断指定配达时间 是否超过7天 大于7天 则异常
                if (StringUtils.isNotBlank(amzOrder.getDeliveryDate()) && status0Flag && orderDo.getPayTime() != null) {
                    try {
                        Date deliverDate = DateUtil.parse(amzOrder.getDeliveryDate(), "yyyy-MM-dd");
                        if (DateUtil.offsetDay(deliverDate, -7).isAfter(new Date())) {
                            orderDo.setStatus(StaticDict.Platform_Order_Status.Five.getValue());
                            orderDo.setExceptionCause("指定配达日期:" + amzOrder.getDeliveryDate() + " 超过7天");
                        } else {
                            orderDo.setStatus(StaticDict.Platform_Order_Status.Zero.getValue());
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                if (oldOrder != null && oldOrder.getPayTime() != null && (orderDo.getStatus() == null || orderDo.getStatus() == oldOrder.getStatus())) {
                    continue;
                }
                //支付方式
                if (amzOrder.getSettlementModel() != null) {
                    orderDo.setSettlementModel(amzOrder.getSettlementModel().getSettlementMethod());
                }

                //买家信息
                if (amzOrder.getOrdererModel() != null) {
                    orderDo.setBuyerName(amzOrder.getOrdererModel().getBuyerName());
                    orderDo.setBuyerEmail(amzOrder.getOrdererModel().getEmailAddress());
                    orderDo.setBuyerPostcode(amzOrder.getOrdererModel().getZipCode());
                    orderDo.setBuyerAddress(amzOrder.getOrdererModel().getAddress());
                    orderDo.setBuyerTelephone(amzOrder.getOrdererModel().getPhoneNumber());
                }
                //总金额
                if (amzOrder.getTotalPrice() != null) {
                    orderDo.setTotalAmount(BigDecimal.valueOf(amzOrder.getTotalPrice()));
                    orderDo.setCurrencyCode(CountryEnum.JP.getCurrency());
                }
//            if (amzOrder.getRequestPrice() != null) {
//                orderDo.setReqPrice(BigDecimal.valueOf(amzOrder.getRequestPrice()));
//            }
                if (amzOrder.getPostagePrice() != null) {
                    orderDo.setPostagePrice(BigDecimal.valueOf(amzOrder.getPostagePrice()));
                }
                if (amzOrder.getTaxSummaryModelList() != null && !amzOrder.getTaxSummaryModelList().isEmpty()) {
                    orderDo.setTaxRate(amzOrder.getTaxSummaryModelList().get(0).getTaxRate());
                    orderDo.setReqPrice(amzOrder.getTaxSummaryModelList().get(0).getReqPrice());//含税
                    orderDo.setReqPriceTax(amzOrder.getTaxSummaryModelList().get(0).getReqPriceTax());
                    orderDo.setCoupon(amzOrder.getTaxSummaryModelList().get(0).getCouponPrice());
                }
                if (amzOrder.getPointModel() != null) {
                    orderDo.setPoint(new BigDecimal(amzOrder.getPointModel().getUsedPoint()));
                }
                if (amzOrder.getPointModel() != null) {
                    orderDo.setPoint(new BigDecimal(amzOrder.getPointModel().getUsedPoint()));
                }
                orderDo.setOrderType(amzOrder.getOrderType());
                orderDo.setIsolated(amzOrder.getIsolatedIslandFlag());
                orderDo.setReserveFlag(0);
                boolean ciRiDaflag = false;
                int puTongType = 0;//普通单时效类型 0没有 1 1-3天内 2 2-5天内
                Date begin = null;
                Date end = null;
                for (ItemModelListEntity itemEntity : packageModelListEntity.getItemModelList()) {
                    if (StringUtils.isNotBlank(itemEntity.getDelvdateInfo()) && itemEntity.getDelvdateInfo().contains("【予約】") && itemEntity.getDelvdateInfo().contains("に出荷")) {
                        //获取预约单子表的 预约时间 并更新到主表
                        Calendar c = Calendar.getInstance();
                        c.setTime(orderDo.getOrderTime());
                        int year = c.get(Calendar.YEAR);
                        String dateStr = itemEntity.getDelvdateInfo().substring(itemEntity.getDelvdateInfo().indexOf("【予約】") + 4, itemEntity.getDelvdateInfo().indexOf("に出荷"));
                        Date itemBegin, itemEnd;
                        if (dateStr.contains("旬")) {
                            //中旬 下旬
                            StringBuilder month = new StringBuilder(dateStr.substring(0, dateStr.indexOf("旬") - 2));
                            if (month.length() < 2) {
                                month.insert(0, "0");
                            }
                            itemBegin = DateUtils.stringFormatToDate(year + "-" + month.toString() + "-08");
                            itemEnd = DateUtils.passingDate(itemBegin, 30);
                        } else {
                            String[] split = dateStr.split("〜");
                            //结束日期在订单日期之前     结束年+1  开始日期在订单日期之前 则也+1
                            if (DateUtils.stringFormatToDate(year + "/" + split[1], "yyyy/MM/dd").before(orderDo.getOrderTime())) {
                                //预约结束日期在订单日期之前
                                itemEnd = DateUtils.stringFormatToDate((year + 1) + "/" + split[1], "yyyy/MM/dd");
                                if (DateUtils.stringFormatToDate(year + "/" + split[1], "yyyy/MM/dd").after(DateUtils.stringFormatToDate(year + "/" + split[0], "yyyy/MM/dd"))) {
                                    //预约开始时间 在结束日期之前 就跟着结束日期 一样 +1
                                    itemBegin = DateUtils.stringFormatToDate((year + 1) + "/" + split[0], "yyyy/MM/dd");
                                } else {
                                    itemBegin = DateUtils.stringFormatToDate((year) + "/" + split[0], "yyyy/MM/dd");
                                }
                            } else {
                                itemEnd = DateUtils.stringFormatToDate((year) + "/" + split[1], "yyyy/MM/dd");
                                itemBegin = DateUtils.stringFormatToDate((year) + "/" + split[0], "yyyy/MM/dd");
                            }
                            long day = DateUtil.betweenDay(new Date(), itemBegin, false);
                            if (day > 160) {
                                //如果预约时间 和当前时间 大于160天 则年减-1
                                itemBegin = DateUtils.passingDateYear(itemBegin, -1);
                                itemEnd = DateUtils.passingDateYear(itemEnd, -1);
                            }
                        }
                        if (end == null || itemEnd.after(end)) {
                            end = itemEnd;
                            begin = itemBegin;
                        } else if (itemEnd.getTime() == end.getTime() && (begin == null || itemBegin.after(begin))) {
                            begin = itemBegin;
                        }
                    } else if ("kk".equals(customer) && StringUtils.isNotBlank(itemEntity.getDelvdateInfo()) && itemEntity.getDelvdateInfo().contains("【予約】") && itemEntity.getDelvdateInfo().contains("に順次発送")) {
                        //KK 预约单 【予約】7月上旬に順次発送！  【予約】06月20日に順次発送！
                        //获取预约单子表的 预约时间 并更新到主表
                        try {
                            Calendar c = Calendar.getInstance();
                            c.setTime(orderDo.getOrderTime());
                            int year = c.get(Calendar.YEAR);
                            String dateStr = itemEntity.getDelvdateInfo().substring(itemEntity.getDelvdateInfo().indexOf("【予約】") + 4, itemEntity.getDelvdateInfo().indexOf("に順次発送"));
                            Date itemBegin, itemEnd;
                            if (dateStr.contains("旬")) {
                                //中旬 下旬
                                StringBuilder month = new StringBuilder(dateStr.substring(0, dateStr.indexOf("旬") - 2));
                                if (month.length() < 2) {
                                    month.insert(0, "0");
                                }
                                itemBegin = DateUtils.stringFormatToDate(year + "-" + month.toString() + "-08");
                                itemEnd = DateUtils.passingDate(itemBegin, 30);
                            } else {
                                Date delvdate = DateUtils.stringFormatToDate(year + "年" + dateStr, "yyyy年MM月dd日");
                                if (delvdate.before(orderDo.getOrderTime())) {
                                    //预约结束日期在订单日期之前
                                    itemBegin = DateUtils.stringFormatToDate((year + 1) + "年" + dateStr, "yyy年MM月dd日");
                                } else {
                                    itemBegin = DateUtils.stringFormatToDate((year) + "年" + dateStr, "yyy年MM月dd日");
                                }
                                itemEnd = DateUtils.passingDate(itemBegin, 30);
                            }
                            if (end == null || itemEnd.after(end)) {
                                end = itemEnd;
                                begin = itemBegin;
                            } else if (itemEnd.getTime() == end.getTime() && (begin == null || itemBegin.after(begin))) {
                                begin = itemBegin;
                            }
                        } catch (Exception e) {
                            end = null;
                            begin = null;
                            e.printStackTrace();
                            log.error("乐天订单解析预约单失败:" + itemEntity.getDelvdateInfo());
                        }
                    }
                    //todo 4077 公司 Amazon Yahoo Wowma平台订单 都分成次日达  或者 deliveryDate 不为空
                    else if (StringUtils.isNotBlank(itemEntity.getDelvdateInfo()) &&
                            (itemEntity.getDelvdateInfo().contains("12時まで") || (itemEntity.getDelvdateInfo().contains("決済日から") && StringUtils.isNotBlank(amzOrder.getDeliveryDate())))) {
                        //次日达
                        ciRiDaflag = true;
                    } else {
                        //普通单
                        if (StringUtils.isNotBlank(itemEntity.getDelvdateInfo()) && itemEntity.getDelvdateInfo().contains("1〜3日以内")) {
                            puTongType = 1;
                        } else if (StringUtils.isNotBlank(itemEntity.getDelvdateInfo()) && itemEntity.getDelvdateInfo().contains("2〜5日以内") && puTongType != 1) {
                            puTongType = 2;
                        }
                    }
                }
                //每一个包裹就是一单
                orderDo.setReceiver(packageModelListEntity.getSenderModel().getSenderName());
                orderDo.setTelephone(packageModelListEntity.getSenderModel().getPhoneNumber());
                orderDo.setCountryRegionCode(CountryEnum.JP.toString());
                orderDo.setProvinceCode(null);
                orderDo.setProvinceName(null);
                orderDo.setCityCode(packageModelListEntity.getSenderModel().getCity());
                orderDo.setDistrict(packageModelListEntity.getSenderModel().getPrefecture());
                orderDo.setPostcode(packageModelListEntity.getSenderModel().getZipCode());
                orderDo.setHouseNum("");
                orderDo.setAddressOne(packageModelListEntity.getSenderModel().getSubAddress());
                orderDo.setAddressTwo(null);
                orderDo.setBasketId(String.valueOf(packageModelListEntity.getBasketId()));
                if (end != null) {
                    orderDo.setReserveBeginTime(begin);
                    orderDo.setReserveEndTime(end);
                    orderDo.setReserveFlag(1);
                } else if (ciRiDaflag) {
                    orderDo.setReserveFlag(2);
                } else {
                    if (puTongType != 0) {
                        //1-3天内
                        orderDo.setReserveBeginTime(orderDo.getOrderTime());
                        String endStr = DateUtils.dateFormatToString(DateUtils.passingDate(orderDo.getReserveBeginTime(), puTongType == 1 ? 3 : 5), "yyyy-MM-dd");
                        endStr += " 23:59:59";
                        orderDo.setReserveEndTime(DateUtils.stringFormatToDateHms(endStr));
                    }
                }
                //处理中的状态是否也要过滤
                StringBuilder builder = new StringBuilder();
                orderDo.setDefaultDeliveryCompanyCode(packageModelListEntity.getDefaultDeliveryCompanyCode());
                for (ItemModelListEntity itemEntity : packageModelListEntity.getItemModelList()) {
                    PlatformOrderProductDo platItem = new PlatformOrderProductDo();
                    platItem.setPlatformOrderNo(platformOrderNo);
                    platItem.setPlatformParentSku(itemEntity.getManageNumber());
                    platItem.setPlatformSku(itemEntity.getItemNumber());
                    if (itemEntity.getSkuModelList() != null && !itemEntity.getSkuModelList().isEmpty()) {
                        platItem.setPlatformSku(itemEntity.getSkuModelList().get(0).getMerchantDefinedSkuId());
                    }
                    if (StringUtils.isBlank(platItem.getPlatformSku())) {
                        platItem.setPlatformSku(itemEntity.getManageNumber());
                    }
                    platItem.setPlatformProductName(itemEntity.getItemName());
                    platItem.setPlatformQty(itemEntity.getUnits());
                    platItem.setSkuType(1);
                    platItem.setItemAmount(BigDecimal.valueOf(itemEntity.getPrice()));
                    platItem.setCurrencyCode(CountryEnum.JP.getCurrency());
                    StringBuilder skuInfo = new StringBuilder();
                    if (itemEntity.getSkuModelList() != null && !itemEntity.getSkuModelList().isEmpty()) {
                        skuInfo.append(itemEntity.getSkuModelList().get(0).getSkuInfo());
                    }
                    if (StringUtils.isNotBlank(itemEntity.getSelectedChoice())) {
                        if (skuInfo.length() > 0) {
                            skuInfo.append("\n");
                        }
                        skuInfo.append(itemEntity.getSelectedChoice());
                    }
                    platItem.setSkuInfo(skuInfo.toString());
                    platItem.setDelvdateInfo(itemEntity.getDelvdateInfo());
                    if (StringUtils.isNotBlank(builder)) {
                        builder.append(";");
                    }
                    builder.append(platItem.getPlatformSku()).append("*").append(platItem.getPlatformQty());
                    if (oldOrder != null) {
                        platItem.setOrderId(oldOrder.getId());
                        platUpdateItems.add(platItem);
                    } else {
                        platInsetItems.add(platItem);
                    }
                }
                if (builder.length() > 100) {
                    builder.delete(100, builder.length());
                }
                orderDo.setPlatformSku(builder.toString());
                if (oldOrder != null) {//只更主表不更新子表
                    if (Objects.equals(orderDo.getStatus(), oldOrder.getStatus()) && (Objects.equals(oldOrder.getPayTime(), orderDo.getPayTime()))) {
                        //状态一致 忽略
                        continue;
                    }
                    orderDo.setId(oldOrder.getId());
                    platUpdateList.add(orderDo);
                } else {
                    confirmMaillList.add(orderDo.getPlatformOrderNo());
                    platInertList.add(orderDo);
                }

            }
        }
        if (!platInertList.isEmpty()) {
            platformOrderService.matchSystemSku(platInsetItems, storeDo.getId(), storeDo.getCompanyId(), storeDo.getTenantId());
            Map<String, List<PlatformOrderProductDo>> skuMap = platInsetItems.stream().filter(i -> StringUtils.isNotBlank(i.getSku())).collect(Collectors.groupingBy(PlatformOrderProductDo::getPlatformOrderNo));
            List<PlatformOrderDo> insertList = platInertList.stream().filter(i -> skuMap.containsKey(i.getPlatformOrderNo())).collect(Collectors.toList());
            for (PlatformOrderDo orderDo : insertList) {
                if (skuMap.get(orderDo.getPlatformOrderNo()) == null) {
                    continue;
                }
                StringBuilder builder = new StringBuilder();
                for (PlatformOrderProductDo productDo : skuMap.get(orderDo.getPlatformOrderNo())) {
                    if (StringUtils.isNotBlank(builder.toString())) {
                        builder.append(";");
                    }
                    builder.append(productDo.getSku()).append("*").append(productDo.getQty());
                }
                if (builder.length() > 100) {
                    builder.delete(100, builder.length());
                }
                orderDo.setSku(builder.toString());
            }
            platformOrderDao.insertPlatformOrder(platInertList);
            for (PlatformOrderDo orderDo : platInertList) {
                //去赋值 orderId
                platInsetItems.stream().filter(i -> i.getPlatformOrderNo().equals(orderDo.getPlatformOrderNo())).forEach(item -> item.setOrderId(orderDo.getId()));
            }
        }
        //插入子表
        if (!platInsetItems.isEmpty()) {
            platformOrderProductDao.insertPlatformOrderItems(platInsetItems);
        }
        if (!platUpdateList.isEmpty()) {
            //再交给rabbitMq 去更新子表
            for (PlatformOrderDo orderDo : platUpdateList) {
                List<PlatformOrderDo> array = new ArrayList<>(Collections.singletonList(orderDo));
                List<PlatformOrderProductDo> collect = platUpdateItems.stream().filter(i -> Objects.equals(orderDo.getId(), i.getOrderId())).collect(Collectors.toList());
                rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_Rakuten_Update, JSON.toJSONString(new RakutenOrderUpdateConReq(array, collect, storeDo.getId(), storeDo.getCompanyId(), storeDo.getTenantId())));

            }
        }
        //完成
        List<SyncRecordItemReq> items = platInertList.stream().map(i -> new SyncRecordItemReq(i.getId(), i.getPlatformOrderNo(), storeDo.getId(), storeDo.getCompanyId())).collect(Collectors.toList());
        rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformOrder_SyncRecord_Update, JSON.toJSONString(new PlatformOrderSyncRecordReq(req.getSyncId(), 2, new Date(), null, null, platInertList.size(), items)));
        //自动发送邮箱
        List<Long> successIds = platInertList.stream().filter(i -> confirmMaillList.contains(i.getPlatformOrderNo())).map(PlatformOrderDo::getId).collect(Collectors.toList());
        rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformOrder_Auto_SendMail, JSON.toJSONString(new SendMailConsumerReq(1, storeDo.getId(), successIds)));
        if (flag) {
            rabbitTemplate.convertAndSend(RabbitQueueConstant.StockToPlatform_CreateStockToPlatformAfterSync, storeDo.getId() + "");
        }
        return "";
    }


    @Override
    public void testGetOrderByTime(String startDate, String endDate, List<String> orderNumbers, Integer dateType, Long storeId, Long userId) {
        List<PlatformStoreDo> storeDoList = new ArrayList<>();
        if (storeId == null) {
            storeDoList = platformStoreDao.selectList(new LambdaQueryWrapper<PlatformStoreDo>().eq(PlatformStoreDo::getPlatformCode, "rakuten")
                    .eq(PlatformStoreDo::getAuthSyncStatus, 1).isNotNull(PlatformStoreDo::getAppSecret));
        }
        else {
            PlatformStoreDo platformStoreDo = platformStoreDao.selectById(storeId);
            if (platformStoreDo == null || platformStoreDo.getAuthSyncStatus() != 1) {
                return;
            }
            storeDoList.add(platformStoreDo);
        }
        for (PlatformStoreDo platformStoreDo : storeDoList) {
            RakutenSyncReq consumerReq = new RakutenSyncReq(new int[]{100, 200, 300, 400, 500, 600, 700, 800, 900},
                    StringUtils.isNotBlank(startDate) ? DateUtils.stringFormatToDate(startDate, "yyyy-MM-dd HH:mm:ss") : null,
                    StringUtils.isNotBlank(endDate) ? DateUtils.stringFormatToDate(endDate, "yyyy-MM-dd HH:mm:ss") : null,
                    orderNumbers,
                    dateType, platformStoreDo.getId(), platformStoreDo.getStoreName(), null, userId);
            if (storeDoList.size() == 1) {
                this.updateRakutenOrders(consumerReq);
            }
            else {
                rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformStore_Rakuten_Sync, JSON.toJSONString(consumerReq));
            }

        }
    }


    @Override
    public RakutenApiRes testGetOrderByNumber(String orderNumber, Long storeId) {
        PlatformStoreDo storeDo = platformStoreDao.selectById(storeId);
        Set<String> orderIds = new HashSet<>(Arrays.asList(orderNumber.split(",")));

        RakutenApiRes order = this.getOrder(orderIds, storeDo);

        return order;
    }

    public RakutenApiRes getOrder(Set<String> orderIds, PlatformStoreDo storeDo) {
        if (orderIds.isEmpty()) return new RakutenApiRes();
        String url = GlobalConstants.RakutenURL + "/order/getOrder/";
        List<List<String>> partition = ListUtil.partition(new ArrayList<>(orderIds), 100);

        List<RakutenOrderModel> orderList = new ArrayList<>();
        for (List<String> orderLimit : partition) {
            Map<String, Object> param = new HashMap<>();
            //如果 order以 -1 -2 结尾则替换掉
            for (int i = 0; i < orderLimit.size(); i++) {
                if (orderLimit.get(i).endsWith("-1") || orderLimit.get(i).endsWith("-2") || orderLimit.get(i).endsWith("-3") || orderLimit.get(i).endsWith("-4")
                    || orderLimit.get(i).endsWith("-5") || orderLimit.get(i).endsWith("-6")) {
                    orderLimit.set(i, orderLimit.get(i).substring(0, orderLimit.get(i).length() - 2));
                }
            }
            param.put("orderNumberList", orderLimit);
            param.put("version", 7);
            String jsonData = "";
            try {
                jsonData = RakutenUtil.raAPidoPOST(url, storeDo.getAppSecret(), storeDo.getAppKey(), param);
                //{ "Results": { "errorCode": "ES01-01", "message": "Un-Authorised"}}
                //{"MessageModelList":[{"messageType":"INFO","messageCode":"ORDER_EXT_API_GET_ORDER_INFO_101","message":"受注情報取得に成功しました。(取得件数1件)"}],"OrderModelList":[{"orderNumber":"369266-20211215-00042704","orderProgress":300,"subStatusId":null,"subStatusName":null,"orderDatetime":"2021-12-15T23:56:00+0900","shopOrderCfmDatetime":"2021-12-16T01:00:01+0900","orderFixDatetime":"2021-12-16T01:03:16+0900","shippingInstDatetime":"2021-12-16T01:03:16+0900","shippingCmplRptDatetime":null,"cancelDueDate":"2022-12-15","deliveryDate":"2021-12-17","shippingTerm":null,"remarks":"[配送日時指定:]\n\n16時過ぎ以降在宅です。\nよろしくお願いします。\n","giftCheckFlag":0,"severalSenderFlag":0,"equalSenderFlag":1,"isolatedIslandFlag":0,"rakutenMemberFlag":1,"carrierCode":12,"emailCarrierCode":0,"orderType":1,"reserveNumber":null,"reserveDeliveryCount":null,"cautionDisplayType":0,"rakutenConfirmFlag":0,"goodsPrice":14280,"goodsTax":0,"postagePrice":0,"deliveryPrice":0,"paymentCharge":0,"paymentChargeTaxRate":0.1,"totalPrice":14280,"requestPrice":13000,"couponAllTotalPrice":0,"couponShopPrice":0,"couponOtherPrice":0,"additionalFeeOccurAmountToUser":0,"additionalFeeOccurAmountToShop":0,"asurakuFlag":1,"drugFlag":0,"dealFlag":0,"membershipType":0,"memo":null,"operator":null,"mailPlugSentence":null,"modifyFlag":0,"receiptIssueCount":0,"receiptIssueHistoryList":[],"OrdererModel":{"zipCode1":"355","zipCode2":"0045","prefecture":"埼玉県","city":"東松山市","subAddress":"宮鼻944-2","familyName":"大湯","firstName":"真沙美","familyNameKana":"オオユ","firstNameKana":"マサミ","phoneNumber1":"0493","phoneNumber2":"34","phoneNumber3":"4466","emailAddress":"2600afad543e82a7a65645b7cc6270b9s1@pc.fw.rakuten.ne.jp","sex":"女","birthYear":1983,"birthMonth":5,"birthDay":25},"SettlementModel":{"settlementMethodCode":1,"settlementMethod":"クレジットカード","rpaySettlementFlag":1,"cardName":"MASTER","cardNumber":"XXXX-XXXX-XXXX-0046","cardOwner":"MASAMI OOYU","cardYm":"2022-05","cardPayType":0,"cardInstallmentDesc":null},"DeliveryModel":{"deliveryName":"宅配便","deliveryClass":null},"PointModel":{"usedPoint":1280},"WrappingModel1":null,"WrappingModel2":null,"PackageModelList":[{"basketId":370494025,"postagePrice":0,"postageTaxRate":0.1,"deliveryPrice":0,"deliveryTaxRate":0.1,"goodsTax":0,"goodsPrice":14280,"totalPrice":14280,"noshi":null,"defaultDeliveryCompanyCode":"1002","packageDeleteFlag":0,"SenderModel":{"zipCode1":"355","zipCode2":"0045","prefecture":"埼玉県","city":"東松山市","subAddress":"宮鼻944-2","familyName":"大湯","firstName":"真沙美","familyNameKana":"オオユ","firstNameKana":"マサミ","phoneNumber1":"0493","phoneNumber2":"34","phoneNumber3":"4466","isolatedIslandFlag":0},"ItemModelList":[{"itemDetailId":370494025,"itemName":"★【クリスマスプレゼントｘP10倍】あす楽送料無料 ゲーミングチェア オフィスチェアMeseracing デスクチェア 高機能チェア パソコンチェア PUレザー 高反発高密度50Dウレタン ゲーム","itemId":10000197,"itemNumber":"mwpo-141PP00141CAA","manageNumber":"mwpo-104","price":14280,"units":1,"includePostageFlag":0,"includeTaxFlag":1,"includeCashOnDeliveryPostageFlag":0,"selectedChoice":"カラー:グレー\n選択:選択\n※納期について、ご確認ください。:確認しました。\n※北海道・離島などの地方では別途追加送料【2500円】がかかります。沖縄県への配送はできかねます。あす楽希望の場合、日付の指定は無しでも大丈夫です。お届け時間帯の指定は可能です。:確認しました。\n※ご注文後の注文内容（カラー）変更はお受付致しかねます。配送先の間違いがございますと、別途【転送料金】が発生します。再度ご確認ください。:確認しました。","pointRate":10,"pointType":1,"inventoryType":2,"delvdateInfo":"午後14時まであす楽対応(日曜日を除く)","restoreInventoryFlag":0,"dealFlag":0,"drugFlag":0,"deleteItemFlag":0,"taxRate":0.1,"priceTaxIncl":14280,"isSingleItemShipping":0}],"ShippingModelList":[],"DeliveryCvsModel":null}],"CouponModelList":null,"ChangeReasonModelList":[{"changeId":1514822970,"changeType":8,"changeTypeDetail":null,"changeReason":null,"changeReasonDetail":null,"changeApplyDatetime":"2021-12-16T01:00:01+0900","changeFixDatetime":"2021-12-16T01:00:01+0900","changeCmplDatetime":"2021-12-16T01:00:01+0900"}],"TaxSummaryModelList":[{"taxRate":0.1,"reqPrice":13000,"reqPriceTax":1181,"totalPrice":14280,"paymentCharge":0,"couponPrice":0,"point":1280}],"DueDateModelList":[]}]}
//                System.out.println("同步的订单：" + jsonData);
            } catch (Exception e) {
                e.printStackTrace();
            }
//            if ("guramu".equals(storeDo.getStoreCode())) {
//                log.error("乐天根据订单号 同步返回值："+ jsonData);
//            }
            if (StringUtils.isBlank(jsonData)) {
                return new RakutenApiRes(500, "连接超时");
            }
            JSONObject object = JSONObject.parseObject(jsonData);
            JSONObject result = object.getJSONObject("Results");
            if (result != null) {
                return new RakutenApiRes(500, result.getString("message"));
            }
            List<RakutenOrderModel> orderModels = JSONObject.parseArray(object.getJSONArray("OrderModelList").toJSONString(), RakutenOrderModel.class);
            orderList.addAll(orderModels);
        }
        return new RakutenApiRes(200, orderList, "");
    }


    @Override
    public void consumerUpdate(RakutenOrderUpdateConReq req) {
        if (CollUtil.isEmpty(req.getEts())) {
            return;
        }
        for (PlatformOrderDo et : req.getEts()) {
            platformOrderDao.updateById(et);
        }
        //如果取消订单去掉 ec订单的取消接口
        List<String> collect = req.getEts().stream().filter(et -> et.getStatus() != null && et.getStatus() == 4).map(PlatformOrderDo::getPlatformOrderNo).collect(Collectors.toList());
        if (CollUtil.isEmpty(collect)) {
            return;
        }
        rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformOrder_CancelForBound, JSON.toJSONString(new PlatformOrderCancelReq(req.getEts().get(0).getStoreId(), collect)));
    }


    private Date replaceStrDateFormat(String orderDatetime) {
        if (StringUtils.isBlank(orderDatetime)) return null;
        String replace = orderDatetime.replace("T", " ").replace("+0900", "");
        return DateUtils.stringFormatToDateHms(replace);
    }


    /**
     * 标发订单
     */
    @Override
    public void markShip(RakutenMarkShipConsumerReq req) {
        RakutenApiRes apiRes = this.markShipPost(req);
        if (apiRes.getCode() != 200 && req.getIdMap() != null) {
            List<Long> ids = new ArrayList<>(req.getIdMap().values());
            platformOrderService.updateMarkStatus(ids, 2, apiRes.getMsg());
            List<OperateRecordDo> operateRecordDos = new ArrayList<>();
            for (Long orderId : ids) {
                OperateRecordDo operateRecordDo = new OperateRecordDo(orderId, OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_MarkShip_Fail, req.getUserId(), new Date(), "密钥过期");
                operateRecordDos.add(operateRecordDo);

            }
            if (!operateRecordDos.isEmpty()) {
                List<List<OperateRecordDo>> recordPartition = ListUtil.partition(operateRecordDos, 3000);
                for (List<OperateRecordDo> partList : recordPartition) {
                    rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
                }
            }
        }
    }


    public RakutenApiRes markShipPost(RakutenMarkShipConsumerReq req) {
        PlatformStoreDo storeDo = platformStoreDao.selectById(req.getStoreId());
        if (storeDo == null || StringUtils.isBlank(storeDo.getAppSecret()) || storeDo.getAuthSyncStatus() != 1) {
            return new RakutenApiRes(500, "密钥过期");
        }
        List<List<RakutenOrderShippingModelRequest>> partition = ListUtil.partition(req.getMarks(), 100);
        String url = GlobalConstants.RakutenURL + "/order/updateOrderShippingAsync/";
        List<RakutenMarkRecordDo> requestId = new ArrayList<>();
        List<RakutenMarkRecordOrderDo> recordOrderDos = new ArrayList<>();
        Map<String, List<Long>> failMap = new HashMap<>();//失败原因map
        for (List<RakutenOrderShippingModelRequest> shipList : partition) {
            Map<String, Object> param = new HashMap<>();
            param.put("OrderShippingModelList", shipList);
            if (shipList.size() == 1) {
                log.info("乐天标发参数：" + JSON.toJSONString(shipList));
            }
            String jsonData = RakutenUtil.raAPidoPOST(url, storeDo.getAppSecret(), storeDo.getAppKey(), param);
            if (StringUtils.isBlank(jsonData)) {
                for (RakutenOrderShippingModelRequest rakutenOrderShippingModelRequest : shipList) {
                    String idMapKey = rakutenOrderShippingModelRequest.getOrderNumber() + "_" + rakutenOrderShippingModelRequest.getBasketidModelList().get(0).getBasketId();
                    failMap.computeIfAbsent("rakuten服务器连接超时", k -> new ArrayList<>()).add(req.getIdMap().get(idMapKey));
                }
                continue;
            }
            if (shipList.size() == 1) {
                log.info("乐天标发返回值：" + jsonData);
            }
            JSONObject object = JSONObject.parseObject(jsonData);
            //{"MessageModelList":[{"messageType":"INFO","messageCode":"ORDER_EXT_API_UPDATE_ORDERSHIPPING_ASYNC_INFO_101","message":"発送情報の更新を受付けました。","requestId":"9c32dcb4-38d5-4224-b632-aa0daf623940_20250617185857","dataNumber":null,"shippingDetailId":null}]}
            List<MessageModel> messageModels = JSONObject.parseArray(object.getString("MessageModelList"), MessageModel.class);
            if (messageModels == null) {
                //{ "Results": { "errorCode": "ES01-03", "message": "Forbidden- Exceeded QPS Limitation"}}
                JSONObject results = object.getJSONObject("Results");
                String markError = results == null ? null : results.getString("message");
                log.error("标发失败意外：" + jsonData);
                for (RakutenOrderShippingModelRequest rakutenOrderShippingModelRequest : shipList) {
                    String idMapKey = rakutenOrderShippingModelRequest.getOrderNumber() + "_" + rakutenOrderShippingModelRequest.getBasketidModelList().get(0).getBasketId();
                    failMap.computeIfAbsent("标发失败", k -> new ArrayList<>()).add(req.getIdMap().get(idMapKey));
                }
            } else {
                for (MessageModel messageModel : messageModels) {
                    if (StringUtils.isNotBlank(messageModel.getRequestId())) {
                        //成功
                        requestId.add(new RakutenMarkRecordDo("rakuten", messageModel.getRequestId(), req.getStoreId(), req.getUserId(), req.getCompanyId()));
                        for (RakutenOrderShippingModelRequest rakutenOrderShippingModelRequest : shipList) {
                            String idMapKey = rakutenOrderShippingModelRequest.getOrderNumber() + "_" + rakutenOrderShippingModelRequest.getBasketidModelList().get(0).getBasketId();
                            recordOrderDos.add(new RakutenMarkRecordOrderDo(messageModel.getRequestId(), req.getIdMap().get(idMapKey)));
                        }
                    } else {
//                        failMap.computeIfAbsent(messageModel.getMessage(), k -> new ArrayList<>()).add(req.getIdMap().get(messageModel.getOrderNumber()));
                        for (RakutenOrderShippingModelRequest rakutenOrderShippingModelRequest : shipList) {
                            String idMapKey = rakutenOrderShippingModelRequest.getOrderNumber() + "_" + rakutenOrderShippingModelRequest.getBasketidModelList().get(0).getBasketId();
                            failMap.computeIfAbsent(messageModel.getMessage(), k -> new ArrayList<>()).add(req.getIdMap().get(idMapKey));
                        }
                    }
                }
            }
        }
        List<Long> values = new ArrayList<>(req.getIdMap().values());
        List<OperateRecordDo> operateRecordDos = new ArrayList<>();
        if (!failMap.isEmpty()) {
            for (String message : failMap.keySet()) {
                platformOrderService.updateMarkStatus(failMap.get(message), 2, message);
                for (Long orderId : failMap.get(message)) {
                    OperateRecordDo operateRecordDo = new OperateRecordDo(orderId, OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_MarkShip_Fail, req.getUserId(), new Date(), message);
                    operateRecordDos.add(operateRecordDo);
                }
                values.removeAll(failMap.get(message));
            }
        }
        if (!values.isEmpty()) {//标发中
            platformOrderService.updateMarkStatus(values, 1, null);
            for (Long orderId : values) {
                OperateRecordDo operateRecordDo = new OperateRecordDo(orderId, OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_MarkShip_ing_No, req.getUserId(), new Date(), req.getTrackNap().get(orderId));
                operateRecordDos.add(operateRecordDo);
            }
        }
        //其他的先改成标发中
        //保存requestId .定时去请求 刷新标发状态
        if (!requestId.isEmpty()) {
            rakutenMarkRecordService.insertBatchMy(requestId);
            for (RakutenMarkRecordDo markRecordDo : requestId) {
                recordOrderDos.stream().filter(i -> Objects.equals(i.getRequestId(), markRecordDo.getRequestId())).forEach(i -> i.setMarkId(markRecordDo.getId()));
            }
            rakutenMarkRecordOrderService.insertBatchMy(recordOrderDos);
        }
        if (!operateRecordDos.isEmpty()) {
            List<List<OperateRecordDo>> recordPartition = ListUtil.partition(operateRecordDos, 3000);
            for (List<OperateRecordDo> partList : recordPartition) {
                rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
            }
        }
        return new RakutenApiRes(200, "标发请求成功");
    }


    @Override
    public void syncMarkRecord() {
        List<RakutenMarkRecordDo> list = rakutenMarkRecordService.list(new LambdaQueryWrapper<RakutenMarkRecordDo>()
                .eq(RakutenMarkRecordDo::getStatus, 0).eq(RakutenMarkRecordDo::getType, "rakuten")
//                        .eq(RakutenMarkRecordDo::getStoreId, 9L) ////ip被封了 再另一个服务器同步 Rakuten-SPORTS数据
                .ge(RakutenMarkRecordDo::getCreateTime, DateUtils.dateFormatToString(DateUtils.passingDate(new Date(), -1))));
        for (RakutenMarkRecordDo markRecordDo : list) {
            rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformOrder_Rakuten_MarkStatus, markRecordDo.getId());
        }
    }

    /**
     * 通过requestId 向乐天获取标发状态
     */
    @Override
    public void getMarkStatus(Long id) {
        RakutenMarkRecordDo markRecordDo = rakutenMarkRecordService.getById(id);
        if (markRecordDo == null || markRecordDo.getStatus() != 0 || markRecordDo.getRequestCount() > 40) {
            return;
        }
        PlatformStoreDo storeDo = platformStoreDao.selectById(markRecordDo.getStoreId());
        if (storeDo == null) {
            return;
        }
        if (StringUtils.isBlank(storeDo.getAppSecret())) {
            return;
        }
        String url = GlobalConstants.RakutenURL + "/order/getResultUpdateOrderShippingAsync/";
        Map<String, Object> param = new HashMap<>();
        param.put("requestId", markRecordDo.getRequestId());
        String jsonData = RakutenUtil.raAPidoPOST(url, storeDo.getAppSecret(), storeDo.getAppKey(), param);
        if (StringUtils.isBlank(jsonData)) {
            //连接异常
            markRecordDo.setRequestCount(markRecordDo.getRequestCount() + 1);
            rakutenMarkRecordService.updateById(markRecordDo);
            return;
        }
        JSONObject object = JSONObject.parseObject(jsonData);
        List<ResultShippingModel> list = JSONArray.parseArray(object.getString("ResultShippingModelList"), ResultShippingModel.class);
        if (list == null) {
            return;
        }
        List<String> successList = new ArrayList<>();
        Map<String, List<String>> errorMap = new HashMap<>();
        for (ResultShippingModel resultShippingModel : list) {
            String orderNumber = resultShippingModel.getOrderNumber();
            if (StringUtils.isBlank(orderNumber)) { //再次请求就好了
                //指定されたリクエストIDの処理結果は存在しませんでした。
                //requestIdの項目を指定して下さい
//                markRecordDo.setStatus(2);
                markRecordDo.setRequestCount(markRecordDo.getRequestCount() + 1);
                rakutenMarkRecordService.updateById(markRecordDo);
                return;
            }
            if (resultShippingModel.getMessageModelList() == null || resultShippingModel.getMessageModelList().isEmpty()) {
                continue;
            }
            for (MessageModel messageModel : resultShippingModel.getMessageModelList()) {
                if ("ERROR".equalsIgnoreCase(messageModel.getMessageType())) {
                    //失败了
                    errorMap.computeIfAbsent(messageModel.getMessage(), k -> new ArrayList<>()).add(orderNumber);
                } else {
                    //发送完成报告（异步）处理正常结束时
                    successList.add(orderNumber);
                }
                break;
            }
        }
        List<String> allNoList = new ArrayList<>();
        allNoList.addAll(successList);
        allNoList.addAll(errorMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList()));
        if (allNoList.isEmpty()) {
            return;
        }
        List<Long> recordOrderId = rakutenMarkRecordOrderService.list(new LambdaQueryWrapper<RakutenMarkRecordOrderDo>()
                .eq(RakutenMarkRecordOrderDo::getMarkId, id)).stream().map(RakutenMarkRecordOrderDo::getOrderId).collect(Collectors.toList());
        Map<String, Long> orderIdNap = new HashMap<>();
        if (!recordOrderId.isEmpty()) {
            orderIdNap = platformOrderService.listByIds(recordOrderId).stream().collect(Collectors.toMap(PlatformOrderDo::getPlatformOrderNo, PlatformOrderDo::getId, (i1, i2) -> i1));
        }
//        Map<String, Long> orderIdNap = platformOrderService.list(new LambdaQueryWrapper<PlatformOrderDo>().select(PlatformOrderDo::getId, PlatformOrderDo::getPlatformOrderNo).eq(PlatformOrderDo::getPlatformCode, StaticDict.Store_PlatformCode.Rakuten.getValue())
//                        .in(PlatformOrderDo::getPlatformOrderNo, allNoList).eq(PlatformOrderDo::getCompanyId, markRecordDo.getCompanyId())
//                        .eq(PlatformOrderDo::getMarkShipmentStatus, 1)
//                        .gt(PlatformOrderDo::getShipTime, DateUtils.dateFormatToString(DateUtils.passingDate(new Date(), -20))))
//                .stream().collect(Collectors.toMap(PlatformOrderDo::getPlatformOrderNo, PlatformOrderDo::getId, (i1, i2) -> i1));
        //是不是拆单的
        if (recordOrderId.size() == 1) {
            //判断是不是 拆单的
            for (String orderNo : orderIdNap.keySet()) {
                if (orderNo.endsWith("-1") || orderNo.endsWith("-2") || orderNo.endsWith("-3") || orderNo.endsWith("-4") || orderNo.endsWith("-5") || orderNo.endsWith("-6")) {
                    orderIdNap.clear();
                    orderIdNap.put(orderNo.substring(0, orderNo.length() - 2), recordOrderId.get(0));
                }
            }
        }
        markRecordDo.setStatus(1);
        markRecordDo.setRequestCount(markRecordDo.getRequestCount() + 1);
        rakutenMarkRecordService.updateById(markRecordDo);

        List<OperateRecordDo> operateRecordDos = new ArrayList<>();
        List<Long> successIds = new ArrayList<>();
        for (String orderNo : successList) {
            Long orderId = orderIdNap.get(orderNo);
            if (orderId == null) {
                continue;
            }
            successIds.add(orderId);
            OperateRecordDo operateRecordDo = new OperateRecordDo(orderId, OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_MarkShip_None_TrackNo, markRecordDo.getCreateBy(), new Date(), "");
            operateRecordDos.add(operateRecordDo);
        }
        //更新标发状态
        platformOrderService.updateMarkStatus(successIds, 3, null);
        for (String error : errorMap.keySet()) {
            List<Long> errorIds = new ArrayList<>();
            for (String orderNo : errorMap.get(error)) {
                Long orderId = orderIdNap.get(orderNo);
                if (orderId == null) {
                    continue;
                }
                errorIds.add(orderId);
                OperateRecordDo operateRecordDo = new OperateRecordDo(orderId, OperateTypeEnum.PlatformOrder.getValue(), SysConstant.platformOrder_MarkShip_Fail, markRecordDo.getCreateBy(), new Date(), error);
                operateRecordDos.add(operateRecordDo);
            }
            platformOrderService.updateMarkStatus(errorIds, 2, error);
        }

        if (!operateRecordDos.isEmpty()) {
            List<List<OperateRecordDo>> partition = ListUtil.partition(operateRecordDos, 3000);
            for (List<OperateRecordDo> partList : partition) {
                rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
            }
        }
        //队列去发
        rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformOrder_Auto_SendMail, JSON.toJSONString(new SendMailConsumerReq(2, markRecordDo.getStoreId(), successIds)));
    }


    @Override
    public String testSetStock() {
        List<InventoryRakutenEntity> skuSetStockReqs = new ArrayList<>();
        skuSetStockReqs.add(new InventoryRakutenEntity("o1-4", "o1-4sng-1", "ABSOLUTE", 1));
        skuSetStockReqs.add(new InventoryRakutenEntity("o1-4", "o1-4sng-211", "ABSOLUTE", 10));

        PlatformStoreDo storeDoList = platformStoreDao.selectOne(new LambdaQueryWrapper<PlatformStoreDo>().eq(PlatformStoreDo::getPlatformCode, "rakuten")
                .eq(PlatformStoreDo::getAuthSyncStatus, 1).isNotNull(PlatformStoreDo::getAppSecret).last(" limit 1"));
        if (storeDoList == null) {
            return null;
        }
//        return this.setStock(skuSetStockReqs, storeDoList);
        return null;
    }

    @Override
    public void setStockByStoreId(StockToPlatformConsumerReq req) {
        PlatformStoreDo storeDo = platformStoreDao.selectById(req.getStoreId());
        if (storeDo == null) {
            return;
        }
        AsyncJobDo asyncJobDo = asyncJobDao.selectById(req.getJobId());
        if (asyncJobDo == null) {
            return;
        }
        //告诉他正在处理
        rabbitTemplate.convertAndSend(RabbitQueueConstant.Export_AsyncDo_Update, JSON.toJSONString(new AsyncUpdateConsumerReq(req.getJobId(), 1, 0, null)));
        List<PlatformSkuStockDto> skuStockList = productStockDao.getPlatformSkuStockList(Arrays.asList(StaticDict.Store_PlatformCode.Rakuten.getValue()),
                req.getPlatformSkuList(), null, req.getInventoryLink(), Arrays.asList(req.getStoreId()));
        if (skuStockList.isEmpty()) {
            rabbitTemplate.convertAndSend(RabbitQueueConstant.Export_AsyncDo_Finish, JSON.toJSONString(new AsyncFinishConsumerReq(req.getJobId(), null)));
            return;
        }
        List<InventoryRakutenReq> stockList = new ArrayList<>();
        String stockRedisKey = RedisKeyConstants.PLATFORMSTOCK_KEY_PREFIX +customer +"_"+ req.getStoreId();
        // 新增：存储SKU ID与对应库存的映射（用于ZSet的score）
        Map<Long, Integer> small20IdToQuantityMap = new HashMap<>();
        for (PlatformSkuStockDto skuStock : skuStockList) {
            if (skuStock.getSystemProductId() == null) {
                continue;
            }
            if (StringUtils.isBlank(skuStock.getParentSku())) {
                continue;
            }
            if (req.getUserId() == null && skuStock.getHideItem() != null && skuStock.getHideItem() == 1) {
                continue;
            }
            double stockPercent = skuStock.getStockPercent() < 0 || skuStock.getStockPercent() > 1 ? 0.95 : 1 - skuStock.getStockPercent();
            int quantity = (int) (skuStock.getLeftQty() / skuStock.getQty() * stockPercent);
            quantity = Math.min(Math.max(quantity, 0), 99999);
            if (quantity > 0 && quantity <= 20) {
                small20IdToQuantityMap.put(skuStock.getId(), quantity); // 保存ID与库存的映射
            }
            if (quantity <= 20 && req.getUserId() == null) {
                quantity = 0;
            }
            Integer lastQuantity = platformOrderService.getLastRecordedInventory(stockRedisKey, skuStock.getPlatformSku());
            if (lastQuantity == null || !lastQuantity.equals(quantity) || req.getUserId() != null) {
                stockList.add(new InventoryRakutenReq(skuStock.getId(), skuStock.getParentSku(), skuStock.getPlatformSku(), skuStock.getVariantId(), "ABSOLUTE", quantity));
            }
        }

        try {
            String key = asyncJobDo.getJobType() + "_count_" + "_" + asyncJobDo.getCompanyId() + "_" + customer + "_" + DateUtils.dateFormatToString(new Date(), "yyyyMMdd");
            long count = redisTemplate.opsForValue().increment(key, 1);
            redisTemplate.expire(key, 60 * 60 * 25, TimeUnit.SECONDS);
            String fileName = asyncJobDo.getJobName() + "_" + count + ".csv";
            String tempFilePath = omsFilePath + fileName;
            CsvExportParams csvParam = new CsvExportParams();
//            csvParam.setEncoding("Shift-JIS");
            csvParam.setEncoding("UTF-8");
            csvParam.setTextMark("");
            CsvUtils.initCsv(tempFilePath, csvParam, StockToPlatformRecordVo.class);
            List<List<InventoryRakutenReq>> partition = ListUtil.partition(stockList, 400);
            Map<String, String> thisStockMap = new HashMap<>();
            for (List<InventoryRakutenReq> inventoryRakutenEntities : partition) {
                List<InventoryRakutenEntity> stockEntityList = inventoryRakutenEntities.stream().filter(i -> StringUtils.isNotBlank(i.getVariantId())).map(i -> new InventoryRakutenEntity(i.getManageNumber(), i.getVariantId(), i.getMode(), i.getQuantity())).collect(Collectors.toList());
                Map<String, Object> map = new JSONObject();
                map.put("inventories", stockEntityList);
                if (stockEntityList.size() == 1) {
                    log.error("乐天回传库存开始 参数：" + JSON.toJSONString(map));
                }
                String jsonData = RakutenUtil.raAPidoPOST("https://api.rms.rakuten.co.jp/es/2.0/inventories/bulk-upsert", storeDo.getAppSecret(), storeDo.getAppKey(), map);
                if (stockEntityList.size() == 1) {
                    log.error("乐天同步库存返回值json：" + jsonData);
                }
                String error = null;
                if (StringUtils.isNotBlank(jsonData)) {
                    JSONObject object = JSONObject.parseObject(jsonData);
                    JSONArray errors = object.getJSONArray("errors");
                    //{ "Results": { "errorCode": "ES01-01", "message": "Un-Authorised"}}
                    if (errors != null) {
                        JSONObject jsonObject1 = errors.getJSONObject(0);
                        error = jsonObject1 == null ? "Results null" : jsonObject1.toJSONString();
                    }
                }
                //记录一下 店铺 平台sku 上一次回传数量
                List<StockToPlatformRecordVo> list = new ArrayList<>();
                for (InventoryRakutenReq inventoryRakutenEntity : inventoryRakutenEntities) {
                    if (StringUtils.isBlank(error) && StringUtils.isNotBlank(inventoryRakutenEntity.getVariantId())) {
                        //成功
                        list.add(new StockToPlatformRecordVo(inventoryRakutenEntity.getManageNumber(), inventoryRakutenEntity.getPlatformSku(), inventoryRakutenEntity.getQuantity(), "成功", null));
                        thisStockMap.put(inventoryRakutenEntity.getPlatformSku(), String.valueOf(inventoryRakutenEntity.getQuantity()));
                    } else {
                        if (StringUtils.isBlank(inventoryRakutenEntity.getVariantId())) {
                            error = "没有variantId信息";
                        }
                        list.add(new StockToPlatformRecordVo(inventoryRakutenEntity.getManageNumber(), inventoryRakutenEntity.getPlatformSku(), inventoryRakutenEntity.getQuantity(), "失败", error));
                    }
                }
                CsvUtils.appendToCsv(tempFilePath, list);
                rabbitTemplate.convertAndSend(RabbitQueueConstant.Export_AsyncDo_Update, JSON.toJSONString(new AsyncUpdateConsumerReq(req.getJobId(), null, list.size(), null)));
                Thread.sleep(1500);
            }
            if (!thisStockMap.isEmpty() && req.getUserId() == null) {
                //记录本次回传数量至redis
                redisTemplate.opsForHash().putAll(stockRedisKey, thisStockMap);
//                redisTemplate.expire(stockRedisKey, 8, TimeUnit.HOURS);
            }
            //本机文件传到oms上
            String objectNameTemporary = "";
            if (filePath.startsWith("http")) {
                try {
                    objectNameTemporary = AliOss.temporaryFile2(fileName, new File(tempFilePath));
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("导出文件失败" + e.getMessage());
                }
            }
            //文件路径
            String path = fileUrl + objectNameTemporary;
            rabbitTemplate.convertAndSend(RabbitQueueConstant.Export_AsyncDo_Finish, JSON.toJSONString(new AsyncFinishConsumerReq(req.getJobId(), path)));
        } catch (Exception e) {
            e.printStackTrace();
            rabbitTemplate.convertAndSend(RabbitQueueConstant.Export_AsyncDo_Update, JSON.toJSONString(new AsyncUpdateConsumerReq(req.getJobId(), 4, 0, e.getMessage())));
        }
        //用ZSet处理低库存SKU的存储与对比
        rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformProduct_InventoryLess, JSON.toJSONString(new UpdateInventoryLessReq(req.getStoreId(), req.getUserId(), small20IdToQuantityMap)));
    }


    @Override
    public String setStock(List<InventoryRakutenReq> stockList, PlatformStoreDo storeDo, Long userId) {
        log.error("乐天回传库存开始 消费队列：" + stockList.size());
        if (stockList.isEmpty() || stockList.size() > 400) {
            return null;
        }
        List<InventoryRakutenEntity> stockEntityList = stockList.stream().map(i -> new InventoryRakutenEntity(i.getManageNumber(), i.getVariantId(), i.getMode(), i.getQuantity())).collect(Collectors.toList());
        //最多 1400条
        Map<String, Object> map = new JSONObject();
        map.put("inventories", stockEntityList);
        if (stockEntityList.size() == 1) {
            log.error("乐天回传库存开始 参数：" + JSON.toJSONString(map));
        }
        String jsonData = RakutenUtil.raAPidoPOST("https://api.rms.rakuten.co.jp/es/2.0/inventories/bulk-upsert", storeDo.getAppSecret(), storeDo.getAppKey(), map);
        log.error("乐天同步库存返回值json：" + jsonData);
        if (StringUtils.isBlank(jsonData)) {
            //回传成功
            List<OperateRecordDo> operateRecordDos = new ArrayList<>();
            for (InventoryRakutenReq inventory : stockList) {
                String message = StaticDict.Store_PlatformCode.Rakuten.getValue() + SysConstant.operateRecordSeparator + storeDo.getStoreName() + SysConstant.operateRecordSeparator + inventory.getManageNumber() + SysConstant.operateRecordSeparator + inventory.getVariantId() + SysConstant.operateRecordSeparator + inventory.getQuantity();
                OperateRecordDo operateRecordDo = new OperateRecordDo(inventory.getId(), OperateTypeEnum.PlatProduct_StockTO_Platform.getValue(),
                        SysConstant.platProduct_StockTo_Platform_SUCCESS,
                        userId, new Date(), message);
                operateRecordDos.add(operateRecordDo);
            }
            if (!operateRecordDos.isEmpty()) {
                List<List<OperateRecordDo>> recordPartition = ListUtil.partition(operateRecordDos, 3000);
                for (List<OperateRecordDo> partList : recordPartition) {
                    rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
                }
            }
            return null;
        }
        JSONObject object = JSONObject.parseObject(jsonData);
        JSONArray errors = object.getJSONArray("errors");
        //{ "Results": { "errorCode": "ES01-01", "message": "Un-Authorised"}}
        if (errors != null) {
            JSONObject jsonObject1 = errors.getJSONObject(0);
            String msg = jsonObject1 == null ? "Results null" : jsonObject1.toJSONString();
            //操作日志判断错误的情况
            List<OperateRecordDo> operateRecordDos = new ArrayList<>();
            for (InventoryRakutenReq inventory : stockList) {
                String message = StaticDict.Store_PlatformCode.Rakuten.getValue() + SysConstant.operateRecordSeparator + storeDo.getStoreName() + SysConstant.operateRecordSeparator
                        + inventory.getManageNumber() + SysConstant.operateRecordSeparator + inventory.getVariantId() + SysConstant.operateRecordSeparator + inventory.getQuantity()
                        + SysConstant.operateRecordSeparator + msg;
                OperateRecordDo operateRecordDo = new OperateRecordDo(inventory.getId(), OperateTypeEnum.PlatProduct_StockTO_Platform.getValue(),
                        SysConstant.platProduct_StockTo_Platform_Fail,
                        userId, new Date(), message);
                operateRecordDos.add(operateRecordDo);
            }
            if (!operateRecordDos.isEmpty()) {
                List<List<OperateRecordDo>> recordPartition = ListUtil.partition(operateRecordDos, 3000);
                for (List<OperateRecordDo> partList : recordPartition) {
                    rabbitTemplate.convertAndSend(RabbitQueueConstant.CrossMall_CMOrder_OperateList, JSON.toJSONString(partList));
                }
            }

            return msg;
        }
        //日志改成文件格式

        return null;
    }


    @Override
    public void itemSearch() {
        List<PlatformStoreDo> storeDoList = platformStoreDao.selectList(new LambdaQueryWrapper<PlatformStoreDo>().eq(PlatformStoreDo::getPlatformCode, "rakuten")
                .eq(PlatformStoreDo::getAuthSyncStatus, 1).isNotNull(PlatformStoreDo::getAppSecret));
        storeDoList.forEach(storeDo -> {
            rabbitTemplate.convertAndSend(RabbitQueueConstant.GetPlatformProduct_Rakuten, JSON.toJSONString(new ItemUpdateConsumerReq(storeDo, null, null)));
        });
    }


    public String itemSearch(PlatformStoreDo storeDo, String parentSku, String platformSku) {
        if (storeDo == null || StringUtils.isBlank(storeDo.getAppSecret())) {
            return ("店铺对应平台Token未绑定");
        }
        String key = RedisKeyConstants.PlatformProduct_Sync_Flag_ + customer + storeDo.getId();
        Object o = redisTemplate.opsForValue().get(key);
        if (o != null) {
            return storeDo.getStoreCode() + " 正在同步商品";
        }
        redisTemplate.opsForValue().set(key, 1, 20, TimeUnit.MINUTES);
        String url = GlobalConstants.RakutenURL + "/items/search";
        int hits = 100;
        int offset = 0;
        int numFound = 0;
        List<PlatformProductDo> productDoList = new ArrayList<>();
        do {
            Map<String, Object> map = new JSONObject();
            map.put("offset", offset);
            map.put("hits", hits);
            map.put("isCategoryIncluded", true);
            if (StringUtils.isNotBlank(parentSku)) {
                map.put("manageNumber", parentSku);
            }
            if (StringUtils.isNotBlank(platformSku)) {
                map.put("merchantDefinedSkuId", platformSku);
            }
//            map.put("variantId", "variantId");
            String jsonData = null;
            log.info("rakuten itemSearch " + "店铺：" + storeDo.getStoreCode() + ", 同步item请求: \r\n" + JSON.toJSONString(map));
            try {
                jsonData = RakutenUtil.raAPidoGet(url, storeDo.getAppSecret(), storeDo.getAppKey(), map);
            } catch (Exception e) {
                e.printStackTrace();
            }
            log.info("rakuten itemSearch " + "店铺：" + storeDo.getStoreCode() + ", 同步item返回: \r\n" + jsonData);
            if (StringUtils.isBlank(jsonData)) {
                return "连接超时";
            }
            JSONObject object = JSONObject.parseObject(jsonData);
            if (object.getJSONArray("errors") != null) {
                return object.getJSONArray("errors").getJSONObject(0).getString("message");
            }
            offset += hits;
            //{ "Results": { "errorCode": "ES01-01", "message": "Un-Authorised"}}
            //分页信息
            numFound = object.getIntValue("numFound");
            JSONArray results = object.getJSONArray("results");
            for (int i = 0; i < results.size(); i++) {
                JSONObject item = results.getJSONObject(i).getJSONObject("item");
                if (item == null) {
                    continue;
                }
                JSONObject variants = item.getJSONObject("variants");
                if (variants == null) {
                    continue;
                }
                for (String string : variants.keySet()) {
                    JSONObject variant = variants.getJSONObject(string);
                    Boolean hidden = variant.getBoolean("hidden");
//                    if (hidden) {
//                        continue;
//                    }
                    String merchantDefinedSkuId = variant.getString("merchantDefinedSkuId");
                    if (StringUtils.isBlank(merchantDefinedSkuId)) {
                        merchantDefinedSkuId = string;
                    }
                    PlatformProductDo productDo = new PlatformProductDo();
                    productDo.setStoreId(storeDo.getId());
                    productDo.setCompanyId(storeDo.getCompanyId());
                    productDo.setTenantId(storeDo.getTenantId());
                    productDo.setParentSku(item.getString("manageNumber"));
//                    productDo.setPlatLeftQuantity(0);
                    productDo.setHideItem(hidden ? 1 : 0);
                    productDo.setItemName(item.getString("title"));
                    productDo.setPlatformSku(merchantDefinedSkuId);
                    productDo.setProductType(item.getString("genreId"));
                    productDo.setVariantId(string);
                    productDo.setMerchantDefinedSkuId(variant.getString("merchantDefinedSkuId"));

                    //CABINET：https://image.rakuten.co.jp/[SHOP_URL]/cabinet/画像パス
                    //GOLD：https://www.rakuten.ne.jp/gold/[SHOP_URL]/画像パス
                    if (item.getJSONArray("images") != null && !item.getJSONArray("images").isEmpty()) {
                        String type = item.getJSONArray("images").getJSONObject(0).getString("type");
                        String imageUrl = null;
                        if ("CABINET".equals(type)) {
                            imageUrl = "https://image.rakuten.co.jp/" + storeDo.getShopUrl() + "/" + type.toLowerCase() + item.getJSONArray("images").getJSONObject(0).getString("location");
                        } else {
                            imageUrl = "https://image.rakuten.co.jp/" + type.toLowerCase() + "/" + storeDo.getShopUrl() + item.getJSONArray("images").getJSONObject(0).getString("location");
                        }
                        productDo.setImageUrl(imageUrl);
                    }
                    JSONArray category = results.getJSONObject(i).getJSONObject("category").getJSONArray("categoryIds");
                    if (category != null) {
                        List<String> arr = JSONArray.parseArray(category.toJSONString(), String.class);
                        productDo.setProductType(StringUtils.join(arr, ","));
                    }
                    JSONArray varImages = variants.getJSONObject(string).getJSONArray("images");
                    if (varImages != null && !varImages.isEmpty()) {
                        String type = varImages.getJSONObject(0).getString("type");
                        String location = varImages.getJSONObject(0).getString("location");
                    }
                    productDoList.add(productDo);
                }
            }
        } while (offset < numFound);
        //按照父sku 去分流更新
        Map<String, List<PlatformProductDo>> parentSkuMap = productDoList.stream().filter(i -> StringUtils.isNotBlank(i.getParentSku())).collect(Collectors.groupingBy(PlatformProductDo::getParentSku));
        if (StringUtils.isBlank(parentSku) && StringUtils.isBlank(platformSku) && !parentSkuMap.isEmpty()) {
            log.info("乐天店铺："+ storeDo.getStoreCode() +" 同步商品 管理番号：\r\n" + parentSkuMap.keySet());
            //全量同步时 根据管理番号去删除
            LambdaQueryWrapper<PlatformProductDo> selectWrapper = new LambdaQueryWrapper<>();
            selectWrapper.select(PlatformProductDo::getId);
            selectWrapper.notIn(PlatformProductDo::getParentSku, parentSkuMap.keySet());
            selectWrapper.eq(PlatformProductDo::getCompanyId, storeDo.getCompanyId());
            selectWrapper.eq(PlatformProductDo::getStoreId, storeDo.getId());
            List<Long> ids = platformProductService.getBaseMapper().selectList(selectWrapper).stream().map(PlatformProductDo::getId).collect(Collectors.toList());
            if (!ids.isEmpty()) {
                LambdaUpdateWrapper<PlatformProductDo> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.in(PlatformProductDo::getId, ids);
                updateWrapper.set(PlatformProductDo::getDeleteFlag, 1);
                updateWrapper.set(PlatformProductDo::getDeleteBy, -2);
                updateWrapper.set(PlatformProductDo::getDeleteTime, new Date());
                platformProductService.update(updateWrapper);
            }
        }
        boolean delete = StringUtils.isBlank(platformSku);
        for (String parentSkuKey : parentSkuMap.keySet()) {
            rabbitTemplate.convertAndSend(RabbitQueueConstant.PlatformProduct_Rakuten_UpdateByParentSKu, JSON.toJSONString(new PlatformProductSyncReq(parentSkuMap.get(parentSkuKey),
                    StaticDict.Store_PlatformCode.Rakuten.getValue(), delete, storeDo.getId(), storeDo.getCompanyId())));
        }
        redisTemplate.delete(key);
        return null;
    }


    @Override
    public void inventoryGet() {
        List<PlatformStoreDo> storeDoList = platformStoreDao.selectList(new LambdaQueryWrapper<PlatformStoreDo>().eq(PlatformStoreDo::getPlatformCode, "rakuten")
                .eq(PlatformStoreDo::getAuthSyncStatus, 1).isNotNull(PlatformStoreDo::getAppSecret));
        storeDoList.forEach(storeDo -> {
            rabbitTemplate.convertAndSend(RabbitQueueConstant.GetPlatformProduct_Stock_Rakuten, JSON.toJSONString(storeDo));

        });
    }


    @Override
    //同步乐天平台库存
    public String inventoryBulkGetRange(PlatformStoreDo storeDo) {
        if (storeDo == null || StringUtils.isBlank(storeDo.getAppSecret())) {
            return ("店铺对应平台Token未绑定");
        }
        String key = RedisKeyConstants.PlatformProduct_Stock_Sync_Flag_ + storeDo.getId();
        Object o = redisTemplate.opsForValue().get(key);
        if (o != null) {
//            return storeDo.getStoreCode() +" 正在同步商品库存";
        }
        redisTemplate.opsForValue().set(key, 1, 10, TimeUnit.MINUTES);
        int minQuantity = 1;
        int maxQuantity = 500;
        Map<String, Integer> moveMap = new HashMap<>();
        for (int i = 1; i <= 20; i++) {
            this.inventoryBulkGetRangeApi(moveMap, storeDo, minQuantity, maxQuantity);
            if (maxQuantity < 2000) {
                minQuantity = minQuantity + 500;
                maxQuantity = maxQuantity + 500;
            } else {
                minQuantity = minQuantity + 1000;
                maxQuantity = maxQuantity + 1000;
            }
            if (maxQuantity > 10000) {
                break;
            }
        }

        for (String string : moveMap.keySet()) {
            LambdaUpdateWrapper<PlatformProductDo> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(PlatformProductDo::getStoreId, storeDo.getId())
                    .eq(PlatformProductDo::getCompanyId, storeDo.getCompanyId())
                    .eq(PlatformProductDo::getVariantId, string)
                    .set(PlatformProductDo::getPlatLeftQuantity, moveMap.get(string));
            platformProductService.update(updateWrapper);
        }
        LambdaUpdateWrapper<PlatformProductDo> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(PlatformProductDo::getStoreId, storeDo.getId())
                .eq(PlatformProductDo::getCompanyId, storeDo.getCompanyId())
                .notIn(PlatformProductDo::getVariantId, moveMap.keySet())
                .set(PlatformProductDo::getPlatLeftQuantity, 0);
        platformProductService.update(updateWrapper);
        redisTemplate.delete(key);
        return null;
    }


    @Override
    public void inventoryBulkGetRangeApi(Map<String, Integer> moveMap, PlatformStoreDo storeDo, int minQuantity, int maxQuantity) {
        if (minQuantity < 0 || maxQuantity < 0 || minQuantity > maxQuantity) {
            return;
        }
        String url = GlobalConstants.RakutenURL + "/inventories/bulk-get/range";
        Map<String, Object> map = new JSONObject();
        map.put("minQuantity", minQuantity);
        map.put("maxQuantity", maxQuantity);
        String jsonData = null;
        try {
            //最多返回1000
            jsonData = RakutenUtil.raAPidoGet(url, storeDo.getAppSecret(), storeDo.getAppKey(), map);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (StringUtils.isBlank(jsonData)) {
            return;
        }
        JSONObject object = JSONObject.parseObject(jsonData);
        if (object.getJSONArray("errors") != null) {
            JSONObject error = object.getJSONArray("errors").getJSONObject(0);
            //{"errors":[{"code":"IE0116","message":"Too many search results, please change the query of search."}]}
            if ("IE0116".equals(error.getString("code"))) {
                int mid = maxQuantity / 2;
                if (mid != maxQuantity) {
//                    rabbitTemplate.convertAndSend(RabbitQueueConstant.GetPlatformProduct_Stock_Count_Rakuten, JSON.toJSONString(new InventoryGetConsumerReq(storeDo, minQuantity, mid)));
                    this.inventoryBulkGetRangeApi(moveMap, storeDo, minQuantity, mid);
                }
                if ((maxQuantity - mid) != minQuantity) {
//                    rabbitTemplate.convertAndSend(RabbitQueueConstant.GetPlatformProduct_Stock_Count_Rakuten, JSON.toJSONString(new InventoryGetConsumerReq(storeDo, maxQuantity - mid, maxQuantity)));
                    this.inventoryBulkGetRangeApi(moveMap, storeDo, maxQuantity - mid, maxQuantity);
                }
            }
            return;
        }
        //{ "Results": { "errorCode": "ES01-01", "message": "Un-Authorised"}}
        //分页信息
        List<RakutenInventory> inventories = JSONArray.parseArray(object.getJSONArray("inventories").toJSONString(), RakutenInventory.class);
        for (RakutenInventory inventory : inventories) {
            moveMap.put(inventory.getVariantId(), inventory.getQuantity());
        }

    }



    @Override
    public String updateRakutenOrdersHistory(RakutenSyncReq req) {
        PlatformStoreDo storeDo = platformStoreDao.selectById(req.getStoreId());
        if (storeDo == null || StringUtils.isBlank(storeDo.getAppSecret())) {
            return ("店铺对应平台Token未绑定");
        }
        Double time = redisTemplate.opsForZSet().score(RedisKeyConstants.orderSyncTimeSet_Rakuten_History_ + customer, storeDo.getId());
        if (time == null) {
            req.setStartDatetime(DateUtils.passingDateYear(new Date(), -1));
        } else {
            req.setStartDatetime(new Date(time.longValue()));
        }
        req.setEndDatetime(DateUtils.passingDateHour(req.getStartDatetime(), 12));
        long day = DateUtil.betweenDay(req.getEndDatetime(), new Date(), true);
        if (day < 14) {
            return ("时间间隔不能小于14天");
        }
        //记录上次同步结束时间， 每次 同步 12小时数据
        redisTemplate.opsForZSet().add(RedisKeyConstants.orderSyncTimeSet_Rakuten_History_ + customer, storeDo.getId(), req.getEndDatetime().getTime() - 1000);
        Set<String> allOrderIds = new TreeSet<>();
        String url = GlobalConstants.RakutenURL + "/order/searchOrder/";
        int count = 1000;
        int pageNo = 1;
        int totalPages = 0;
        do {
            Map<String, Object> map = new JSONObject();
            map.put("startDatetime", DateUtils.dateFormatToString(req.getStartDatetime(), "yyyy-MM-dd'T'HH:mm:ss+0900"));
            map.put("endDatetime", DateUtils.dateFormatToString(req.getEndDatetime(), "yyyy-MM-dd'T'HH:mm:ss+0900"));
            map.put("dateType", req.getDateType());//1,订单创建时间 3订单支付时间
            map.put("orderProgressList", req.getOrderStatus());
            Map<String, Object> page = new HashMap<>();
            page.put("requestRecordsAmount", count);
            page.put("requestPage", pageNo);
            map.put("PaginationRequestModel", page);
            String jsonData = RakutenUtil.raAPidoPOST(url, storeDo.getAppSecret(), storeDo.getAppKey(), map);
            if (StringUtils.isBlank(jsonData)) {
                redisTemplate.opsForZSet().add(RedisKeyConstants.orderSyncTimeSet_Rakuten_History_ + customer, storeDo.getId(), req.getStartDatetime().getTime());
                return "连接超时";
            }
            JSONObject object = JSONObject.parseObject(jsonData);
            JSONArray messageModelList = object.getJSONArray("MessageModelList");
            //{ "Results": { "errorCode": "ES01-01", "message": "Un-Authorised"}}
            if (messageModelList == null) {
                JSONObject jsonObject1 = object.getJSONObject("Results");
                redisTemplate.opsForZSet().add(RedisKeyConstants.orderSyncTimeSet_Rakuten_History_ + customer, storeDo.getId(), req.getStartDatetime().getTime());
                return jsonObject1 == null ? "Results null" : jsonObject1.toJSONString();
            }
            if ("ERROR".equals(messageModelList.getJSONObject(0).getString("messageType"))) {
                //错误的情况
                String message = messageModelList.getJSONObject(0).getString("message");
                redisTemplate.opsForZSet().add(RedisKeyConstants.orderSyncTimeSet_Rakuten_History_ + customer, storeDo.getId(), req.getStartDatetime().getTime());
                return message;
            } else {
                //分页信息
                JSONObject paginationResponseModel = object.getJSONObject("PaginationResponseModel");
                totalPages = paginationResponseModel.getIntValue("totalPages");
                pageNo = paginationResponseModel.getIntValue("requestPage");
                pageNo++;
                String[] orderIds = object.getJSONArray("orderNumberList").toJavaObject(String[].class);
                //剔除本地 500 的订单 增加本地300的订单
                if (orderIds.length > 0) {
                    allOrderIds.addAll(Arrays.asList(orderIds));
                }
            }
        } while (pageNo <= totalPages);
        RakutenApiRes apiRes = this.getOrder(allOrderIds, storeDo);
        //要插入的
        List<PlatformOrderCopyDo> platInertList = new ArrayList<>();
        for (RakutenOrderModel amzOrder : apiRes.getData()) {
            PlatformOrderCopyDo copyDo = new PlatformOrderCopyDo();
            copyDo.setCompanyId(storeDo.getCompanyId());
            copyDo.setStoreId(storeDo.getId());
            copyDo.setPlatformOrderNo(amzOrder.getOrderNumber());
            copyDo.setOrderTime(this.replaceStrDateFormat(amzOrder.getOrderDatetime()));
            copyDo.setPlatformCode(storeDo.getPlatformCode());
            copyDo.setOrderMsg(JSON.toJSONString(amzOrder));
            platInertList.add(copyDo);
        }
        platformOrderCopyService.batchInsert(platInertList);
        return "";
    }

}
